@dxos/plugin-transcription 0.8.4-main.67995b8 → 0.8.4-main.ae835ea

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.
Files changed (172) hide show
  1. package/dist/lib/browser/TranscriptContainer-2GSL2XB5.mjs +11 -0
  2. package/dist/lib/browser/blueprint-definition-UAAJYVLZ.mjs +150 -0
  3. package/dist/lib/browser/blueprint-definition-UAAJYVLZ.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-U6QBOGTN.mjs → chunk-3MKZ2MNQ.mjs} +5 -5
  5. package/dist/lib/browser/chunk-3MKZ2MNQ.mjs.map +7 -0
  6. package/dist/lib/browser/{chunk-4FJIYH7T.mjs → chunk-535OJKFO.mjs} +2 -2
  7. package/dist/lib/browser/{chunk-5KPYIC3N.mjs → chunk-7DR6HZEF.mjs} +332 -363
  8. package/dist/lib/browser/chunk-7DR6HZEF.mjs.map +7 -0
  9. package/dist/lib/browser/chunk-VBUIO677.mjs +29 -0
  10. package/dist/lib/browser/chunk-VBUIO677.mjs.map +7 -0
  11. package/dist/lib/browser/chunk-W7WKZTM4.mjs +63 -0
  12. package/dist/lib/browser/chunk-W7WKZTM4.mjs.map +7 -0
  13. package/dist/lib/browser/{chunk-FFEPEPCU.mjs → chunk-WH36ENNE.mjs} +49 -78
  14. package/dist/lib/browser/chunk-WH36ENNE.mjs.map +7 -0
  15. package/dist/lib/browser/index.mjs +24 -19
  16. package/dist/lib/browser/index.mjs.map +3 -3
  17. package/dist/lib/browser/intent-resolver-ZTKTEAQX.mjs +25 -0
  18. package/dist/lib/browser/intent-resolver-ZTKTEAQX.mjs.map +7 -0
  19. package/dist/lib/browser/meta.json +1 -1
  20. package/dist/lib/browser/{react-surface-E5D5AE3F.mjs → react-surface-KA32A72I.mjs} +10 -10
  21. package/dist/lib/browser/react-surface-KA32A72I.mjs.map +7 -0
  22. package/dist/lib/browser/{transcriber-PXT4QBFY.mjs → transcriber-LWOLYQHC.mjs} +7 -7
  23. package/dist/lib/browser/transcriber-LWOLYQHC.mjs.map +7 -0
  24. package/dist/lib/browser/types/index.mjs +6 -8
  25. package/dist/lib/node-esm/{TranscriptContainer-VBAOM5DG.mjs → TranscriptContainer-GRLDCESB.mjs} +4 -4
  26. package/dist/lib/node-esm/blueprint-definition-Z3LTZ3ID.mjs +151 -0
  27. package/dist/lib/node-esm/blueprint-definition-Z3LTZ3ID.mjs.map +7 -0
  28. package/dist/lib/node-esm/{chunk-TJKAO7VR.mjs → chunk-K4AZOB5Y.mjs} +332 -363
  29. package/dist/lib/node-esm/chunk-K4AZOB5Y.mjs.map +7 -0
  30. package/dist/lib/node-esm/chunk-OLMSTF3M.mjs +64 -0
  31. package/dist/lib/node-esm/chunk-OLMSTF3M.mjs.map +7 -0
  32. package/dist/lib/node-esm/{chunk-Y2B4HWSS.mjs → chunk-Q6WD7L2J.mjs} +2 -2
  33. package/dist/lib/node-esm/{chunk-RHF2ALML.mjs → chunk-SWUVPFKR.mjs} +5 -5
  34. package/dist/lib/node-esm/chunk-SWUVPFKR.mjs.map +7 -0
  35. package/dist/lib/node-esm/{chunk-HT3W7LDP.mjs → chunk-YFN4FJFK.mjs} +49 -78
  36. package/dist/lib/node-esm/chunk-YFN4FJFK.mjs.map +7 -0
  37. package/dist/lib/node-esm/chunk-YVNQN2J6.mjs +30 -0
  38. package/dist/lib/node-esm/chunk-YVNQN2J6.mjs.map +7 -0
  39. package/dist/lib/node-esm/index.mjs +24 -19
  40. package/dist/lib/node-esm/index.mjs.map +3 -3
  41. package/dist/lib/node-esm/intent-resolver-55WH2GY6.mjs +26 -0
  42. package/dist/lib/node-esm/intent-resolver-55WH2GY6.mjs.map +7 -0
  43. package/dist/lib/node-esm/meta.json +1 -1
  44. package/dist/lib/node-esm/{react-surface-QRDJOHN5.mjs → react-surface-GU7LW2JO.mjs} +10 -10
  45. package/dist/lib/node-esm/react-surface-GU7LW2JO.mjs.map +7 -0
  46. package/dist/lib/node-esm/{transcriber-YUTEVANE.mjs → transcriber-UGB7ECX6.mjs} +7 -7
  47. package/dist/lib/node-esm/transcriber-UGB7ECX6.mjs.map +7 -0
  48. package/dist/lib/node-esm/types/index.mjs +6 -8
  49. package/dist/types/src/TranscriptionPlugin.d.ts +1 -1
  50. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  51. package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
  52. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
  53. package/dist/types/src/capabilities/capabilities.d.ts +1 -1
  54. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  55. package/dist/types/src/capabilities/index.d.ts +3 -2
  56. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  57. package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
  58. package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
  59. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  60. package/dist/types/src/capabilities/transcriber.d.ts +1 -1
  61. package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
  62. package/dist/types/src/components/Transcript/Transcript.d.ts +5 -5
  63. package/dist/types/src/components/Transcript/Transcript.d.ts.map +1 -1
  64. package/dist/types/src/components/Transcript/Transcript.stories.d.ts +31 -16
  65. package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +1 -1
  66. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +3 -3
  67. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +1 -1
  68. package/dist/types/src/components/Transcript/transcript-extension.d.ts +1 -5
  69. package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +1 -1
  70. package/dist/types/src/components/TranscriptContainer.d.ts +2 -2
  71. package/dist/types/src/components/TranscriptContainer.d.ts.map +1 -1
  72. package/dist/types/src/components/stories/FileTranscription.stories.d.ts +5 -4
  73. package/dist/types/src/components/stories/FileTranscription.stories.d.ts.map +1 -1
  74. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts +10 -6
  75. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts.map +1 -1
  76. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts +7 -6
  77. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts.map +1 -1
  78. package/dist/types/src/components/stories/TranscriptionStory.d.ts +2 -1
  79. package/dist/types/src/components/stories/TranscriptionStory.d.ts.map +1 -1
  80. package/dist/types/src/functions/index.d.ts +3 -0
  81. package/dist/types/src/functions/index.d.ts.map +1 -0
  82. package/dist/types/src/functions/open.d.ts +7 -0
  83. package/dist/types/src/functions/open.d.ts.map +1 -0
  84. package/dist/types/src/functions/summarize.d.ts +11 -0
  85. package/dist/types/src/functions/summarize.d.ts.map +1 -0
  86. package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
  87. package/dist/types/src/hooks/useVoiceInput.d.ts.map +1 -1
  88. package/dist/types/src/meta.d.ts +0 -1
  89. package/dist/types/src/meta.d.ts.map +1 -1
  90. package/dist/types/src/segments-normalization/normalization.d.ts +388 -328
  91. package/dist/types/src/segments-normalization/normalization.d.ts.map +1 -1
  92. package/dist/types/src/testing/testing.d.ts +2 -2
  93. package/dist/types/src/testing/testing.d.ts.map +1 -1
  94. package/dist/types/src/transcriber/media-stream-recorder.d.ts +1 -1
  95. package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +1 -1
  96. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  97. package/dist/types/src/transcriber/transcription-manager.d.ts +3 -7
  98. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  99. package/dist/types/src/types/Transcript.d.ts +30 -0
  100. package/dist/types/src/types/Transcript.d.ts.map +1 -0
  101. package/dist/types/src/types/TranscriptAction.d.ts +23 -0
  102. package/dist/types/src/types/TranscriptAction.d.ts.map +1 -0
  103. package/dist/types/src/types/index.d.ts +2 -1
  104. package/dist/types/src/types/index.d.ts.map +1 -1
  105. package/dist/types/src/types/types.d.ts +0 -26
  106. package/dist/types/src/types/types.d.ts.map +1 -1
  107. package/dist/types/tsconfig.tsbuildinfo +1 -1
  108. package/package.json +65 -66
  109. package/src/TranscriptionPlugin.tsx +58 -53
  110. package/src/capabilities/blueprint-definition.ts +31 -0
  111. package/src/capabilities/capabilities.ts +6 -6
  112. package/src/capabilities/index.ts +1 -0
  113. package/src/capabilities/intent-resolver.ts +5 -11
  114. package/src/capabilities/react-surface.tsx +2 -2
  115. package/src/capabilities/transcriber.ts +3 -2
  116. package/src/components/Transcript/Transcript.stories.tsx +34 -31
  117. package/src/components/Transcript/Transcript.tsx +20 -27
  118. package/src/components/Transcript/deprecated/OldTranscript.tsx +9 -9
  119. package/src/components/Transcript/transcript-extension.ts +2 -39
  120. package/src/components/TranscriptContainer.tsx +7 -6
  121. package/src/components/stories/FileTranscription.stories.tsx +47 -36
  122. package/src/components/stories/KeyWordRecognition.stories.tsx +14 -10
  123. package/src/components/stories/MicrophoneTranscription.stories.tsx +40 -37
  124. package/src/components/stories/TranscriptionStory.tsx +10 -6
  125. package/src/functions/index.ts +6 -0
  126. package/src/functions/open.ts +39 -0
  127. package/src/functions/summarize.ts +103 -0
  128. package/src/hooks/useAudioFile.ts +49 -53
  129. package/src/hooks/useVoiceInput.ts +3 -2
  130. package/src/meta.ts +7 -4
  131. package/src/model/model.test.ts +1 -1
  132. package/src/segments-normalization/message-normalizer.ts +1 -1
  133. package/src/segments-normalization/normalization.test.ts +5 -5
  134. package/src/segments-normalization/normalization.ts +38 -37
  135. package/src/testing/testing.ts +7 -7
  136. package/src/transcriber/media-stream-recorder.ts +1 -1
  137. package/src/transcriber/transcriber.browser.test.ts +2 -1
  138. package/src/transcriber/transcriber.ts +2 -1
  139. package/src/transcriber/transcription-manager.ts +17 -38
  140. package/src/types/{schema.ts → Transcript.ts} +12 -9
  141. package/src/types/TranscriptAction.ts +24 -0
  142. package/src/types/index.ts +2 -1
  143. package/src/types/types.ts +0 -23
  144. package/dist/lib/browser/TranscriptContainer-6WCKCXQ6.mjs +0 -11
  145. package/dist/lib/browser/chunk-5KPYIC3N.mjs.map +0 -7
  146. package/dist/lib/browser/chunk-5WH45KBY.mjs +0 -19
  147. package/dist/lib/browser/chunk-5WH45KBY.mjs.map +0 -7
  148. package/dist/lib/browser/chunk-FFEPEPCU.mjs.map +0 -7
  149. package/dist/lib/browser/chunk-R7INNNUQ.mjs +0 -55
  150. package/dist/lib/browser/chunk-R7INNNUQ.mjs.map +0 -7
  151. package/dist/lib/browser/chunk-U6QBOGTN.mjs.map +0 -7
  152. package/dist/lib/browser/intent-resolver-3O33MMP5.mjs +0 -30
  153. package/dist/lib/browser/intent-resolver-3O33MMP5.mjs.map +0 -7
  154. package/dist/lib/browser/react-surface-E5D5AE3F.mjs.map +0 -7
  155. package/dist/lib/browser/transcriber-PXT4QBFY.mjs.map +0 -7
  156. package/dist/lib/node-esm/chunk-HT3W7LDP.mjs.map +0 -7
  157. package/dist/lib/node-esm/chunk-RHF2ALML.mjs.map +0 -7
  158. package/dist/lib/node-esm/chunk-TJKAO7VR.mjs.map +0 -7
  159. package/dist/lib/node-esm/chunk-U65ZWK3L.mjs +0 -56
  160. package/dist/lib/node-esm/chunk-U65ZWK3L.mjs.map +0 -7
  161. package/dist/lib/node-esm/chunk-XMUCZBP3.mjs +0 -21
  162. package/dist/lib/node-esm/chunk-XMUCZBP3.mjs.map +0 -7
  163. package/dist/lib/node-esm/intent-resolver-YMN5SXNC.mjs +0 -31
  164. package/dist/lib/node-esm/intent-resolver-YMN5SXNC.mjs.map +0 -7
  165. package/dist/lib/node-esm/react-surface-QRDJOHN5.mjs.map +0 -7
  166. package/dist/lib/node-esm/transcriber-YUTEVANE.mjs.map +0 -7
  167. package/dist/types/src/types/schema.d.ts +0 -41
  168. package/dist/types/src/types/schema.d.ts.map +0 -1
  169. /package/dist/lib/browser/{TranscriptContainer-6WCKCXQ6.mjs.map → TranscriptContainer-2GSL2XB5.mjs.map} +0 -0
  170. /package/dist/lib/browser/{chunk-4FJIYH7T.mjs.map → chunk-535OJKFO.mjs.map} +0 -0
  171. /package/dist/lib/node-esm/{TranscriptContainer-VBAOM5DG.mjs.map → TranscriptContainer-GRLDCESB.mjs.map} +0 -0
  172. /package/dist/lib/node-esm/{chunk-Y2B4HWSS.mjs.map → chunk-Q6WD7L2J.mjs.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  TranscriptionCapabilities
3
- } from "./chunk-U6QBOGTN.mjs";
3
+ } from "./chunk-3MKZ2MNQ.mjs";
4
4
 
5
5
  // src/components/TranscriptContainer.tsx
6
6
  import { useSignals as _useSignals2 } from "@preact-signals/safe-react/tracking";
@@ -9,28 +9,134 @@ import { fullyQualifiedId, getSpace } from "@dxos/client/echo";
9
9
  import { useMembers, useQueue } from "@dxos/react-client/echo";
10
10
  import { StackItem } from "@dxos/react-ui-stack";
11
11
 
12
- // src/components/Transcript/Transcript.tsx
13
- import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
14
- import React from "react";
15
- import { IconButton, useThemeContext } from "@dxos/react-ui";
16
- import { createBasicExtensions, createMarkdownExtensions, createRenderer, createThemeExtensions, decorateMarkdown, editorWidth, preview, useTextEditor } from "@dxos/react-ui-editor";
17
- import { mx } from "@dxos/react-ui-theme";
18
- import { isNotFalsy } from "@dxos/util";
12
+ // src/hooks/useAudioFile.ts
13
+ import { useEffect, useState } from "react";
14
+ import { scheduleTask } from "@dxos/async";
15
+ import { Context } from "@dxos/context";
16
+ import { log } from "@dxos/log";
17
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useAudioFile.ts";
18
+ var useAudioFile = (audioUrl, constraints) => {
19
+ const [{ audio, stream, track }, setStream] = useState({});
20
+ useEffect(() => {
21
+ const ctx = new Context(void 0, {
22
+ F: __dxlog_file,
23
+ L: 20
24
+ });
25
+ scheduleTask(ctx, async () => {
26
+ try {
27
+ const response = await fetch(audioUrl);
28
+ const blob = await response.blob();
29
+ const objectUrl = URL.createObjectURL(blob);
30
+ ctx.onDispose(() => {
31
+ URL.revokeObjectURL(objectUrl);
32
+ });
33
+ const audio2 = new Audio();
34
+ audio2.src = objectUrl;
35
+ await new Promise((resolve, reject) => {
36
+ audio2.addEventListener("error", (err) => {
37
+ log.error("error", {
38
+ err
39
+ }, {
40
+ F: __dxlog_file,
41
+ L: 39,
42
+ S: void 0,
43
+ C: (f, a) => f(...a)
44
+ });
45
+ reject(err);
46
+ }, {
47
+ once: true
48
+ });
49
+ audio2.addEventListener("canplay", async () => {
50
+ resolve();
51
+ }, {
52
+ once: true
53
+ });
54
+ audio2.load();
55
+ });
56
+ const audioCtx = new AudioContext();
57
+ if (audioCtx.state === "suspended") {
58
+ await audioCtx.resume();
59
+ }
60
+ const destination = audioCtx.createMediaStreamDestination();
61
+ destination.channelCount = 1;
62
+ const source = audioCtx.createMediaElementSource(audio2);
63
+ source.connect(destination);
64
+ const track2 = destination.stream.getAudioTracks()[0];
65
+ if (constraints) {
66
+ await track2.applyConstraints(constraints).catch((err) => log.catch(err, void 0, {
67
+ F: __dxlog_file,
68
+ L: 68,
69
+ S: void 0,
70
+ C: (f, a) => f(...a)
71
+ }));
72
+ }
73
+ setStream({
74
+ audio: audio2,
75
+ stream: destination.stream,
76
+ track: destination.stream.getAudioTracks()[0]
77
+ });
78
+ } catch (err) {
79
+ log.catch(err, void 0, {
80
+ F: __dxlog_file,
81
+ L: 78,
82
+ S: void 0,
83
+ C: (f, a) => f(...a)
84
+ });
85
+ }
86
+ });
87
+ return () => {
88
+ void ctx.dispose();
89
+ };
90
+ }, [
91
+ audioUrl
92
+ ]);
93
+ return {
94
+ audio,
95
+ stream,
96
+ track
97
+ };
98
+ };
19
99
 
20
- // src/components/Transcript/transcript-extension.ts
21
- import { RangeSetBuilder } from "@codemirror/state";
22
- import { EditorView, GutterMarker, ViewPlugin, gutter } from "@codemirror/view";
23
- import { format } from "date-fns/format";
24
- import { intervalToDuration } from "date-fns/intervalToDuration";
25
- import { addEventListener, combine } from "@dxos/async";
100
+ // src/hooks/useAudioTrack.ts
101
+ import { useEffect as useEffect2, useState as useState2 } from "react";
102
+ var useAudioTrack = (active, constraints) => {
103
+ const [track, setTrack] = useState2();
104
+ useEffect2(() => {
105
+ if (!active) {
106
+ track?.stop();
107
+ setTrack(void 0);
108
+ return;
109
+ }
110
+ const initAudio = async () => {
111
+ const audio = new Audio();
112
+ audio.srcObject = await navigator.mediaDevices.getUserMedia({
113
+ audio: constraints ?? true
114
+ });
115
+ const [track2] = audio.srcObject.getAudioTracks();
116
+ if (track2) {
117
+ setTrack(track2);
118
+ }
119
+ };
120
+ if (active) {
121
+ void initAudio();
122
+ }
123
+ }, [
124
+ active
125
+ ]);
126
+ return track;
127
+ };
128
+
129
+ // src/hooks/useQueueModelAdapter.ts
130
+ import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
26
131
 
27
132
  // src/model/model.ts
28
133
  import { Text } from "@codemirror/state";
29
134
  import { Event } from "@dxos/async";
30
135
  import { invariant } from "@dxos/invariant";
31
- import { log } from "@dxos/log";
32
- var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/model/model.ts";
136
+ import { log as log2 } from "@dxos/log";
137
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/model/model.ts";
33
138
  var DocumentAdapter = class {
139
+ _view;
34
140
  constructor(_view) {
35
141
  this._view = _view;
36
142
  }
@@ -39,13 +145,13 @@ var DocumentAdapter = class {
39
145
  return this._view.state.doc.lines - 1;
40
146
  }
41
147
  replaceLines(from, remove, insert) {
42
- log("replaceLines", {
148
+ log2("replaceLines", {
43
149
  count: this._view.state.doc.lines,
44
150
  from,
45
151
  remove,
46
152
  insert
47
153
  }, {
48
- F: __dxlog_file,
154
+ F: __dxlog_file2,
49
155
  L: 39,
50
156
  S: this,
51
157
  C: (f, a) => f(...a)
@@ -67,13 +173,19 @@ var DocumentAdapter = class {
67
173
  }
68
174
  };
69
175
  var SerializationModel = class {
176
+ _renderer;
177
+ /** Ordered set of chunks. */
178
+ _chunks = [];
179
+ /** Map of chunk IDs to their current line counts. */
180
+ _chunkLineCounts = /* @__PURE__ */ new Map();
181
+ /** Map of line numbers to chunk IDs. */
182
+ _lineToChunk = /* @__PURE__ */ new Map();
183
+ /** Track chunk changes since last sync. */
184
+ _changes = [];
185
+ /** Emits when the document is updated. */
186
+ update = new Event();
70
187
  constructor(_renderer, initialChunks = []) {
71
188
  this._renderer = _renderer;
72
- this._chunks = [];
73
- this._chunkLineCounts = /* @__PURE__ */ new Map();
74
- this._lineToChunk = /* @__PURE__ */ new Map();
75
- this._changes = [];
76
- this.update = new Event();
77
189
  initialChunks.forEach((chunk) => {
78
190
  this.appendChunk(chunk);
79
191
  });
@@ -120,7 +232,7 @@ var SerializationModel = class {
120
232
  updateChunk(chunk) {
121
233
  const index = this._chunks.findIndex((c) => c.id === chunk.id);
122
234
  invariant(index !== -1, void 0, {
123
- F: __dxlog_file,
235
+ F: __dxlog_file2,
124
236
  L: 147,
125
237
  S: this,
126
238
  A: [
@@ -140,7 +252,7 @@ var SerializationModel = class {
140
252
  deleteBlock(id) {
141
253
  const index = this._chunks.findIndex((c) => c.id === id);
142
254
  invariant(index !== -1, void 0, {
143
- F: __dxlog_file,
255
+ F: __dxlog_file2,
144
256
  L: 156,
145
257
  S: this,
146
258
  A: [
@@ -161,10 +273,10 @@ var SerializationModel = class {
161
273
  * Syncs the tracked changes with the ChunkDocument.
162
274
  */
163
275
  sync(document2) {
164
- log("sync", {
276
+ log2("sync", {
165
277
  changes: this._changes
166
278
  }, {
167
- F: __dxlog_file,
279
+ F: __dxlog_file2,
168
280
  L: 167,
169
281
  S: this,
170
282
  C: (f, a) => f(...a)
@@ -217,8 +329,172 @@ var SerializationModel = class {
217
329
  }
218
330
  };
219
331
 
332
+ // src/hooks/useQueueModelAdapter.ts
333
+ var useQueueModelAdapter = (renderer, queue, initialChunks = []) => {
334
+ const model = useMemo(() => new SerializationModel(renderer, initialChunks), [
335
+ queue
336
+ ]);
337
+ const [loaded, setLoaded] = useState3(false);
338
+ useEffect3(() => {
339
+ if (!queue) {
340
+ return;
341
+ }
342
+ const update = () => {
343
+ for (const block of queue?.objects ?? []) {
344
+ model.appendChunk(block);
345
+ }
346
+ setLoaded(true);
347
+ };
348
+ let i;
349
+ if (queue.isLoading) {
350
+ i = setInterval(() => {
351
+ if (!queue?.isLoading) {
352
+ clearInterval(i);
353
+ update();
354
+ }
355
+ }, 1e3);
356
+ } else {
357
+ update();
358
+ }
359
+ return () => clearTimeout(i);
360
+ }, [
361
+ model,
362
+ queue
363
+ ]);
364
+ useEffect3(() => {
365
+ if (!loaded || !queue || model.chunks.length === queue.objects.length) {
366
+ return;
367
+ }
368
+ const chunk = queue.objects.at(-1);
369
+ if (chunk) {
370
+ model.appendChunk(chunk);
371
+ }
372
+ }, [
373
+ model,
374
+ loaded,
375
+ queue?.objects.length
376
+ ]);
377
+ return model;
378
+ };
379
+
380
+ // src/hooks/useTranscriber.ts
381
+ import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
382
+ import { useCapabilities } from "@dxos/app-framework";
383
+
384
+ // src/capabilities/index.ts
385
+ import { lazy } from "@dxos/app-framework";
386
+ var BlueprintDefinition = lazy(() => import("./blueprint-definition-UAAJYVLZ.mjs"));
387
+ var IntentResolver = lazy(() => import("./intent-resolver-ZTKTEAQX.mjs"));
388
+ var ReactSurface = lazy(() => import("./react-surface-KA32A72I.mjs"));
389
+ var Transcriber = lazy(() => import("./transcriber-LWOLYQHC.mjs"));
390
+
391
+ // src/hooks/useTranscriber.ts
392
+ var useTranscriber = ({ audioStreamTrack, recorderConfig, transcriberConfig, onSegments }) => {
393
+ const [getTranscriber] = useCapabilities(TranscriptionCapabilities.Transcriber);
394
+ const transcriber = useMemo2(() => {
395
+ if (!getTranscriber || !audioStreamTrack || !onSegments) {
396
+ return void 0;
397
+ }
398
+ return getTranscriber({
399
+ audioStreamTrack,
400
+ recorderConfig,
401
+ transcriberConfig,
402
+ onSegments
403
+ });
404
+ }, [
405
+ getTranscriber,
406
+ audioStreamTrack,
407
+ recorderConfig,
408
+ transcriberConfig,
409
+ onSegments
410
+ ]);
411
+ useEffect4(() => {
412
+ return () => {
413
+ void transcriber?.close();
414
+ };
415
+ }, [
416
+ transcriber
417
+ ]);
418
+ return transcriber;
419
+ };
420
+
421
+ // src/hooks/useVoiceInput.ts
422
+ import { useCallback, useEffect as useEffect5, useState as useState4 } from "react";
423
+ import { scheduleMicroTask } from "@dxos/async";
424
+ import { Context as Context2 } from "@dxos/context";
425
+ import { log as log3 } from "@dxos/log";
426
+ import { useSoundEffect } from "@dxos/react-ui-sfx";
427
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useVoiceInput.ts";
428
+ var useVoiceInput = ({ active, onUpdate }) => {
429
+ const soundStart = useSoundEffect("StartRecording");
430
+ const soundStop = useSoundEffect("StopRecording");
431
+ const handleSegments = useCallback(async (segments) => {
432
+ const text = segments.map((str) => str.text.trim().replace(/[^\w\s]/g, "")).join(" ");
433
+ onUpdate(text);
434
+ }, []);
435
+ const [recording, setRecording] = useState4(false);
436
+ const track = useAudioTrack(active);
437
+ const transcriber = useTranscriber({
438
+ audioStreamTrack: track,
439
+ onSegments: handleSegments
440
+ });
441
+ useEffect5(() => {
442
+ const ctx = new Context2(void 0, {
443
+ F: __dxlog_file3,
444
+ L: 44
445
+ });
446
+ scheduleMicroTask(ctx, async () => {
447
+ if (active && transcriber) {
448
+ await transcriber.open();
449
+ log3.info("starting...", void 0, {
450
+ F: __dxlog_file3,
451
+ L: 48,
452
+ S: void 0,
453
+ C: (f, a) => f(...a)
454
+ });
455
+ setRecording(true);
456
+ void soundStart.play();
457
+ transcriber.startChunksRecording();
458
+ } else if (!active && transcriber?.isOpen) {
459
+ transcriber?.stopChunksRecording();
460
+ await transcriber?.close();
461
+ log3.info("stopped", void 0, {
462
+ F: __dxlog_file3,
463
+ L: 55,
464
+ S: void 0,
465
+ C: (f, a) => f(...a)
466
+ });
467
+ setRecording(false);
468
+ void soundStop.play();
469
+ }
470
+ });
471
+ return () => {
472
+ void ctx.dispose();
473
+ };
474
+ }, [
475
+ active,
476
+ transcriber
477
+ ]);
478
+ return {
479
+ recording
480
+ };
481
+ };
482
+
483
+ // src/components/Transcript/Transcript.tsx
484
+ import { useSignals as _useSignals } from "@preact-signals/safe-react/tracking";
485
+ import React from "react";
486
+ import { useThemeContext } from "@dxos/react-ui";
487
+ import { autoScroll, createBasicExtensions, createMarkdownExtensions, createThemeExtensions, decorateMarkdown, preview, useTextEditor } from "@dxos/react-ui-editor";
488
+ import { mx } from "@dxos/react-ui-theme";
489
+ import { isTruthy } from "@dxos/util";
490
+
220
491
  // src/components/Transcript/transcript-extension.ts
221
- var transcript = ({ model, started, renderButton }) => {
492
+ import { RangeSetBuilder } from "@codemirror/state";
493
+ import { EditorView, GutterMarker, ViewPlugin, gutter } from "@codemirror/view";
494
+ import { format } from "date-fns/format";
495
+ import { intervalToDuration } from "date-fns/intervalToDuration";
496
+ import { addEventListener, combine } from "@dxos/async";
497
+ var transcript = ({ model, started }) => {
222
498
  return [
223
499
  // Show timestamps in the gutter.
224
500
  gutter({
@@ -246,8 +522,11 @@ var transcript = ({ model, started, renderButton }) => {
246
522
  }),
247
523
  // Listen for model updates.
248
524
  ViewPlugin.fromClass(class {
525
+ _controls;
526
+ _cleanup;
527
+ _adapter;
528
+ _initialized = false;
249
529
  constructor(view) {
250
- this._initialized = false;
251
530
  this._adapter = new DocumentAdapter(view);
252
531
  const scroller = view.scrollDOM;
253
532
  let isAutoScrolling = false;
@@ -269,30 +548,20 @@ var transcript = ({ model, started, renderButton }) => {
269
548
  })
270
549
  });
271
550
  };
272
- if (renderButton) {
273
- this._controls = document.createElement("div");
274
- this._controls.classList.add("cm-controls", "transition-opacity", "duration-300", "opacity-0");
275
- view.dom.appendChild(this._controls);
276
- renderButton(this._controls, {
277
- onClick: () => {
278
- scrollToBottom(false);
279
- }
280
- }, view);
281
- }
282
551
  this._cleanup = combine(addEventListener(view.scrollDOM, "scroll", () => {
283
552
  if (!isAutoScrolling) {
284
553
  hasScrolled = true;
285
554
  this._controls?.classList.remove("opacity-0");
286
555
  }
287
556
  }), model.update.on(() => {
288
- const autoScroll = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight === 0 || !hasScrolled;
557
+ const autoScroll2 = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight === 0 || !hasScrolled;
289
558
  model.sync(this._adapter);
290
- if (autoScroll) {
559
+ if (autoScroll2) {
291
560
  scrollToBottom(true);
292
561
  }
293
562
  }));
294
563
  }
295
- update(update) {
564
+ update(_update) {
296
565
  if (!this._initialized) {
297
566
  this._initialized = true;
298
567
  setTimeout(() => {
@@ -306,25 +575,6 @@ var transcript = ({ model, started, renderButton }) => {
306
575
  }
307
576
  }),
308
577
  EditorView.theme({
309
- ".cm-scroller": {
310
- overflowY: "scroll"
311
- },
312
- ".cm-hide-scrollbar": {
313
- scrollbarWidth: "none",
314
- "-ms-overflow-style": "none"
315
- },
316
- ".cm-hide-scrollbar::-webkit-scrollbar": {
317
- display: "none"
318
- },
319
- ".cm-controls": {
320
- position: "absolute",
321
- bottom: "0.5rem",
322
- right: "0.5rem",
323
- zIndex: 1e3
324
- },
325
- ".cm-line": {
326
- paddingRight: "1rem"
327
- },
328
578
  ".cm-timestamp-gutter": {
329
579
  width: "6rem",
330
580
  paddingRight: "1rem"
@@ -338,6 +588,9 @@ var transcript = ({ model, started, renderButton }) => {
338
588
  ];
339
589
  };
340
590
  var TimestampMarker = class extends GutterMarker {
591
+ _line;
592
+ _timestamp;
593
+ _started;
341
594
  constructor(_line, _timestamp, _started) {
342
595
  super(), this._line = _line, this._timestamp = _timestamp, this._started = _started;
343
596
  }
@@ -382,7 +635,7 @@ var formatTimestamp = (timestamp, relative) => {
382
635
  };
383
636
 
384
637
  // src/components/Transcript/Transcript.tsx
385
- var renderMarkdown = (identities) => (message, index, debug = false) => {
638
+ var renderByline = (identities) => (message, index, debug = false) => {
386
639
  if (message.sender.role === "assistant") {
387
640
  return [
388
641
  message.blocks.find((block) => block._tag === "transcript")?.text ?? "",
@@ -393,12 +646,13 @@ var renderMarkdown = (identities) => (message, index, debug = false) => {
393
646
  const name = identity?.profile?.displayName ?? message.sender.contact?.target?.fullName ?? message.sender.name ?? message.sender.email ?? message.sender.identityDid;
394
647
  const blocks = message.blocks.filter((block) => block._tag === "transcript");
395
648
  return [
649
+ // TODO(thure): Use an XML tag with the bits needed here.
396
650
  `###### ${name}` + (debug ? ` [${index}]:${message.id}` : ""),
397
651
  blocks.map((block) => block.text.trim()).join(" "),
398
652
  ""
399
653
  ];
400
654
  };
401
- var Transcript = ({ classNames, transcript: object, space, model, attendableId, ignoreAttention }) => {
655
+ var TranscriptView = ({ classNames, space, transcript: object, model }) => {
402
656
  var _effect = _useSignals();
403
657
  try {
404
658
  const { themeMode } = useThemeContext();
@@ -407,27 +661,21 @@ var Transcript = ({ classNames, transcript: object, space, model, attendableId,
407
661
  extensions: [
408
662
  createBasicExtensions({
409
663
  readOnly: true,
410
- lineWrapping: true
411
- }),
412
- createMarkdownExtensions({
413
- themeMode
664
+ lineWrapping: true,
665
+ search: true
414
666
  }),
667
+ createMarkdownExtensions(),
415
668
  createThemeExtensions({
416
669
  themeMode
417
670
  }),
418
671
  decorateMarkdown(),
419
- space && preview(),
672
+ preview(),
420
673
  transcript({
421
674
  model,
422
- started: object?.started ? new Date(object.started) : void 0,
423
- renderButton: createRenderer(({ onClick }) => /* @__PURE__ */ React.createElement(IconButton, {
424
- icon: "ph--arrow-line-down--regular",
425
- iconOnly: true,
426
- label: "Scroll to bottom",
427
- onClick
428
- }))
429
- })
430
- ].filter(isNotFalsy)
675
+ started: object?.started ? new Date(object.started) : void 0
676
+ }),
677
+ autoScroll()
678
+ ].filter(isTruthy)
431
679
  };
432
680
  }, [
433
681
  space,
@@ -435,7 +683,7 @@ var Transcript = ({ classNames, transcript: object, space, model, attendableId,
435
683
  ]);
436
684
  return /* @__PURE__ */ React.createElement("div", {
437
685
  ref: parentRef,
438
- className: mx("flex grow overflow-hidden", editorWidth, classNames),
686
+ className: mx("flex grow overflow-hidden container-max-width", classNames),
439
687
  "data-popover-collision-boundary": true
440
688
  });
441
689
  } finally {
@@ -443,284 +691,6 @@ var Transcript = ({ classNames, transcript: object, space, model, attendableId,
443
691
  }
444
692
  };
445
693
 
446
- // src/hooks/useAudioFile.ts
447
- import { useEffect, useState } from "react";
448
- import { scheduleTask } from "@dxos/async";
449
- import { Context } from "@dxos/context";
450
- import { log as log2 } from "@dxos/log";
451
- var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useAudioFile.ts";
452
- var useAudioFile = (audioUrl, constraints) => {
453
- const [{ audio, stream, track }, setStream] = useState({});
454
- useEffect(() => {
455
- const ctx = new Context(void 0, {
456
- F: __dxlog_file2,
457
- L: 20
458
- });
459
- scheduleTask(ctx, async () => {
460
- const response = await fetch(audioUrl);
461
- const blob = await response.blob();
462
- const objectUrl = URL.createObjectURL(blob);
463
- ctx.onDispose(() => {
464
- URL.revokeObjectURL(objectUrl);
465
- });
466
- const audio2 = new Audio();
467
- audio2.src = objectUrl;
468
- await new Promise((resolve, reject) => {
469
- audio2.addEventListener("error", (err) => {
470
- log2.error("error", {
471
- err
472
- }, {
473
- F: __dxlog_file2,
474
- L: 37,
475
- S: void 0,
476
- C: (f, a) => f(...a)
477
- });
478
- reject(err);
479
- }, {
480
- once: true
481
- });
482
- audio2.addEventListener("canplay", async () => {
483
- log2.info("starting...", void 0, {
484
- F: __dxlog_file2,
485
- L: 45,
486
- S: void 0,
487
- C: (f, a) => f(...a)
488
- });
489
- try {
490
- await audio2.play();
491
- resolve();
492
- } catch (playError) {
493
- log2.error("Play failed", {
494
- playError
495
- }, {
496
- F: __dxlog_file2,
497
- L: 51,
498
- S: void 0,
499
- C: (f, a) => f(...a)
500
- });
501
- resolve();
502
- }
503
- }, {
504
- once: true
505
- });
506
- audio2.load();
507
- });
508
- const audioCtx = new AudioContext();
509
- if (audioCtx.state === "suspended") {
510
- await audioCtx.resume();
511
- }
512
- const destination = audioCtx.createMediaStreamDestination();
513
- destination.channelCount = 1;
514
- const source = audioCtx.createMediaElementSource(audio2);
515
- source.connect(destination);
516
- const track2 = destination.stream.getAudioTracks()[0];
517
- if (constraints) {
518
- await track2.applyConstraints(constraints).catch((err) => log2.catch(err, void 0, {
519
- F: __dxlog_file2,
520
- L: 75,
521
- S: void 0,
522
- C: (f, a) => f(...a)
523
- }));
524
- }
525
- setStream({
526
- audio: audio2,
527
- stream: destination.stream,
528
- track: destination.stream.getAudioTracks()[0]
529
- });
530
- });
531
- return () => {
532
- void ctx.dispose();
533
- };
534
- }, [
535
- audioUrl
536
- ]);
537
- return {
538
- audio,
539
- stream,
540
- track
541
- };
542
- };
543
-
544
- // src/hooks/useAudioTrack.ts
545
- import { useEffect as useEffect2, useState as useState2 } from "react";
546
- var useAudioTrack = (active, constraints) => {
547
- const [track, setTrack] = useState2();
548
- useEffect2(() => {
549
- if (!active) {
550
- track?.stop();
551
- setTrack(void 0);
552
- return;
553
- }
554
- const initAudio = async () => {
555
- const audio = new Audio();
556
- audio.srcObject = await navigator.mediaDevices.getUserMedia({
557
- audio: constraints ?? true
558
- });
559
- const [track2] = audio.srcObject.getAudioTracks();
560
- if (track2) {
561
- setTrack(track2);
562
- }
563
- };
564
- if (active) {
565
- void initAudio();
566
- }
567
- }, [
568
- active
569
- ]);
570
- return track;
571
- };
572
-
573
- // src/hooks/useQueueModelAdapter.ts
574
- import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
575
- var useQueueModelAdapter = (renderer, queue, initialChunks = []) => {
576
- const model = useMemo(() => new SerializationModel(renderer, initialChunks), [
577
- queue
578
- ]);
579
- const [loaded, setLoaded] = useState3(false);
580
- useEffect3(() => {
581
- if (!queue) {
582
- return;
583
- }
584
- const update = () => {
585
- for (const block of queue?.objects ?? []) {
586
- model.appendChunk(block);
587
- }
588
- setLoaded(true);
589
- };
590
- let i;
591
- if (queue.isLoading) {
592
- i = setInterval(() => {
593
- if (!queue?.isLoading) {
594
- clearInterval(i);
595
- update();
596
- }
597
- }, 1e3);
598
- } else {
599
- update();
600
- }
601
- return () => clearTimeout(i);
602
- }, [
603
- model,
604
- queue
605
- ]);
606
- useEffect3(() => {
607
- if (!loaded || !queue || model.chunks.length === queue.objects.length) {
608
- return;
609
- }
610
- const chunk = queue.objects.at(-1);
611
- if (chunk) {
612
- model.appendChunk(chunk);
613
- }
614
- }, [
615
- model,
616
- loaded,
617
- queue?.objects.length
618
- ]);
619
- return model;
620
- };
621
-
622
- // src/hooks/useTranscriber.ts
623
- import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
624
- import { useCapabilities } from "@dxos/app-framework";
625
-
626
- // src/capabilities/index.ts
627
- import { lazy } from "@dxos/app-framework";
628
- var IntentResolver = lazy(() => import("./intent-resolver-3O33MMP5.mjs"));
629
- var ReactSurface = lazy(() => import("./react-surface-E5D5AE3F.mjs"));
630
- var Transcriber = lazy(() => import("./transcriber-PXT4QBFY.mjs"));
631
-
632
- // src/hooks/useTranscriber.ts
633
- var useTranscriber = ({ audioStreamTrack, recorderConfig, transcriberConfig, onSegments }) => {
634
- const [getTranscriber] = useCapabilities(TranscriptionCapabilities.Transcriber);
635
- const transcriber = useMemo2(() => {
636
- if (!getTranscriber || !audioStreamTrack || !onSegments) {
637
- return void 0;
638
- }
639
- return getTranscriber({
640
- audioStreamTrack,
641
- recorderConfig,
642
- transcriberConfig,
643
- onSegments
644
- });
645
- }, [
646
- getTranscriber,
647
- audioStreamTrack,
648
- recorderConfig,
649
- transcriberConfig,
650
- onSegments
651
- ]);
652
- useEffect4(() => {
653
- return () => {
654
- void transcriber?.close();
655
- };
656
- }, [
657
- transcriber
658
- ]);
659
- return transcriber;
660
- };
661
-
662
- // src/hooks/useVoiceInput.ts
663
- import { useState as useState4, useEffect as useEffect5, useCallback } from "react";
664
- import { scheduleMicroTask } from "@dxos/async";
665
- import { Context as Context2 } from "@dxos/context";
666
- import { log as log3 } from "@dxos/log";
667
- import { useSoundEffect } from "@dxos/react-ui-sfx";
668
- var __dxlog_file3 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useVoiceInput.ts";
669
- var useVoiceInput = ({ active, onUpdate }) => {
670
- const soundStart = useSoundEffect("StartRecording");
671
- const soundStop = useSoundEffect("StopRecording");
672
- const handleSegments = useCallback(async (segments) => {
673
- const text = segments.map((str) => str.text.trim().replace(/[^\w\s]/g, "")).join(" ");
674
- onUpdate(text);
675
- }, []);
676
- const [recording, setRecording] = useState4(false);
677
- const track = useAudioTrack(active);
678
- const transcriber = useTranscriber({
679
- audioStreamTrack: track,
680
- onSegments: handleSegments
681
- });
682
- useEffect5(() => {
683
- const ctx = new Context2(void 0, {
684
- F: __dxlog_file3,
685
- L: 43
686
- });
687
- scheduleMicroTask(ctx, async () => {
688
- if (active && transcriber) {
689
- await transcriber.open();
690
- log3.info("starting...", void 0, {
691
- F: __dxlog_file3,
692
- L: 47,
693
- S: void 0,
694
- C: (f, a) => f(...a)
695
- });
696
- setRecording(true);
697
- void soundStart.play();
698
- transcriber.startChunksRecording();
699
- } else if (!active && transcriber?.isOpen) {
700
- transcriber?.stopChunksRecording();
701
- await transcriber?.close();
702
- log3.info("stopped", void 0, {
703
- F: __dxlog_file3,
704
- L: 54,
705
- S: void 0,
706
- C: (f, a) => f(...a)
707
- });
708
- setRecording(false);
709
- void soundStop.play();
710
- }
711
- });
712
- return () => {
713
- void ctx.dispose();
714
- };
715
- }, [
716
- active,
717
- transcriber
718
- ]);
719
- return {
720
- recording
721
- };
722
- };
723
-
724
694
  // src/components/TranscriptContainer.tsx
725
695
  var TranscriptionContainer = ({ transcript: transcript2 }) => {
726
696
  var _effect = _useSignals2();
@@ -731,10 +701,8 @@ var TranscriptionContainer = ({ transcript: transcript2 }) => {
731
701
  const queue = useQueue(transcript2.queue.dxn, {
732
702
  pollInterval: 1e3
733
703
  });
734
- const model = useQueueModelAdapter(renderMarkdown(members), queue);
735
- return /* @__PURE__ */ React2.createElement(StackItem.Content, {
736
- classNames: "container-max-width pli-2"
737
- }, /* @__PURE__ */ React2.createElement(Transcript, {
704
+ const model = useQueueModelAdapter(renderByline(members), queue);
705
+ return /* @__PURE__ */ React2.createElement(StackItem.Content, null, /* @__PURE__ */ React2.createElement(TranscriptView, {
738
706
  attendableId,
739
707
  space,
740
708
  model,
@@ -747,8 +715,8 @@ var TranscriptionContainer = ({ transcript: transcript2 }) => {
747
715
  var TranscriptContainer_default = TranscriptionContainer;
748
716
 
749
717
  export {
750
- renderMarkdown,
751
- Transcript,
718
+ renderByline,
719
+ TranscriptView,
752
720
  useAudioFile,
753
721
  useAudioTrack,
754
722
  useQueueModelAdapter,
@@ -756,8 +724,9 @@ export {
756
724
  useVoiceInput,
757
725
  TranscriptionContainer,
758
726
  TranscriptContainer_default,
727
+ BlueprintDefinition,
759
728
  IntentResolver,
760
729
  ReactSurface,
761
730
  Transcriber
762
731
  };
763
- //# sourceMappingURL=chunk-5KPYIC3N.mjs.map
732
+ //# sourceMappingURL=chunk-7DR6HZEF.mjs.map