@dxos/plugin-transcription 0.8.4-main.9be5663bfe → 0.8.4-main.abd8ff62ef

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 (201) hide show
  1. package/dist/lib/browser/blueprints/index.mjs +1 -1
  2. package/dist/lib/browser/blueprints/index.mjs.map +3 -3
  3. package/dist/lib/browser/{chunk-5LWSJZTZ.mjs → chunk-3L623EVL.mjs} +2 -2
  4. package/dist/lib/browser/chunk-3L623EVL.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-HOOPZ7EM.mjs → chunk-KAEXRX3Y.mjs} +1 -1
  6. package/dist/lib/browser/{chunk-RIUSFL62.mjs → chunk-L4HW35L6.mjs} +4 -5
  7. package/dist/lib/browser/chunk-L4HW35L6.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-MLRJWAQH.mjs +179 -0
  9. package/dist/lib/browser/chunk-MLRJWAQH.mjs.map +7 -0
  10. package/dist/lib/browser/chunk-NQQK7UZQ.mjs +244 -0
  11. package/dist/lib/browser/chunk-NQQK7UZQ.mjs.map +7 -0
  12. package/dist/lib/browser/components/index.mjs +207 -0
  13. package/dist/lib/browser/components/index.mjs.map +7 -0
  14. package/dist/lib/browser/{create-IZPB7VZW.mjs → create-ULR5DPJZ.mjs} +6 -4
  15. package/dist/lib/browser/create-ULR5DPJZ.mjs.map +7 -0
  16. package/dist/lib/browser/hooks/index.mjs +17 -0
  17. package/dist/lib/browser/hooks/index.mjs.map +7 -0
  18. package/dist/lib/browser/index.mjs +93 -831
  19. package/dist/lib/browser/index.mjs.map +4 -4
  20. package/dist/lib/browser/meta.json +1 -1
  21. package/dist/lib/browser/open-SFMPLZVW.mjs +27 -0
  22. package/dist/lib/browser/open-SFMPLZVW.mjs.map +7 -0
  23. package/dist/lib/browser/operations/index.mjs +3 -3
  24. package/dist/lib/browser/operations/index.mjs.map +3 -3
  25. package/dist/lib/browser/{summarize-5MZENAU5.mjs → summarize-BDFX4APN.mjs} +15 -8
  26. package/dist/lib/browser/summarize-BDFX4APN.mjs.map +7 -0
  27. package/dist/lib/browser/types/index.mjs +1 -1
  28. package/dist/lib/node-esm/blueprints/index.mjs +1 -1
  29. package/dist/lib/node-esm/blueprints/index.mjs.map +3 -3
  30. package/dist/lib/node-esm/{chunk-3GSFEN4L.mjs → chunk-7UIZWCD4.mjs} +4 -5
  31. package/dist/lib/node-esm/chunk-7UIZWCD4.mjs.map +7 -0
  32. package/dist/lib/node-esm/chunk-C3AE2NYJ.mjs +181 -0
  33. package/dist/lib/node-esm/chunk-C3AE2NYJ.mjs.map +7 -0
  34. package/dist/lib/node-esm/{chunk-X74WYCCE.mjs → chunk-KO3IOD2O.mjs} +2 -2
  35. package/dist/lib/node-esm/chunk-KO3IOD2O.mjs.map +7 -0
  36. package/dist/lib/node-esm/chunk-MQK4R6GT.mjs +245 -0
  37. package/dist/lib/node-esm/chunk-MQK4R6GT.mjs.map +7 -0
  38. package/dist/lib/node-esm/{chunk-NVM2QUMX.mjs → chunk-O533NBMK.mjs} +1 -1
  39. package/dist/lib/node-esm/components/index.mjs +208 -0
  40. package/dist/lib/node-esm/components/index.mjs.map +7 -0
  41. package/dist/lib/node-esm/{create-TQDGXQBL.mjs → create-A5QHNWRF.mjs} +6 -4
  42. package/dist/lib/node-esm/create-A5QHNWRF.mjs.map +7 -0
  43. package/dist/lib/node-esm/hooks/index.mjs +18 -0
  44. package/dist/lib/node-esm/hooks/index.mjs.map +7 -0
  45. package/dist/lib/node-esm/index.mjs +93 -831
  46. package/dist/lib/node-esm/index.mjs.map +4 -4
  47. package/dist/lib/node-esm/meta.json +1 -1
  48. package/dist/lib/node-esm/open-OI24QNTO.mjs +28 -0
  49. package/dist/lib/node-esm/open-OI24QNTO.mjs.map +7 -0
  50. package/dist/lib/node-esm/operations/index.mjs +3 -3
  51. package/dist/lib/node-esm/operations/index.mjs.map +3 -3
  52. package/dist/lib/node-esm/{summarize-RVOSRHEC.mjs → summarize-3UNN24I2.mjs} +15 -8
  53. package/dist/lib/node-esm/summarize-3UNN24I2.mjs.map +7 -0
  54. package/dist/lib/node-esm/types/index.mjs +1 -1
  55. package/dist/types/src/TranscriptionPlugin.d.ts +1 -0
  56. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  57. package/dist/types/src/TranscriptionPlugin.node.d.ts +4 -0
  58. package/dist/types/src/TranscriptionPlugin.node.d.ts.map +1 -0
  59. package/dist/types/src/TranscriptionPlugin.test.d.ts +2 -0
  60. package/dist/types/src/TranscriptionPlugin.test.d.ts.map +1 -0
  61. package/dist/types/src/blueprints/transcription-blueprint.d.ts +2 -2
  62. package/dist/types/src/blueprints/transcription-blueprint.d.ts.map +1 -1
  63. package/dist/types/src/capabilities/blueprint-definition.d.ts +2 -2
  64. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
  65. package/dist/types/src/capabilities/index.d.ts +2 -2
  66. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  67. package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
  68. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -1
  69. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  70. package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
  71. package/dist/types/src/components/Transcription/Transcription.d.ts +1 -1
  72. package/dist/types/src/components/Transcription/Transcription.stories.d.ts +7 -7
  73. package/dist/types/src/components/Transcription/Transcription.stories.d.ts.map +1 -1
  74. package/dist/types/src/components/Transcription/transcription-extension.d.ts.map +1 -1
  75. package/dist/types/src/containers/TranscriptionContainer/TranscriptionContainer.d.ts.map +1 -1
  76. package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
  77. package/dist/types/src/hooks/useAudioTrack.d.ts.map +1 -1
  78. package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +1 -1
  79. package/dist/types/src/hooks/useTranscriber.d.ts +1 -1
  80. package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
  81. package/dist/types/src/hooks/useVoiceInput.d.ts.map +1 -1
  82. package/dist/types/src/index.d.ts +3 -3
  83. package/dist/types/src/index.d.ts.map +1 -1
  84. package/dist/types/src/model/model.d.ts +2 -2
  85. package/dist/types/src/model/model.d.ts.map +1 -1
  86. package/dist/types/src/{segments-normalization → normalization}/index.d.ts +1 -1
  87. package/dist/types/src/normalization/index.d.ts.map +1 -0
  88. package/dist/types/src/normalization/message-normalizer.d.ts.map +1 -0
  89. package/dist/types/src/{segments-normalization → normalization}/normalization.d.ts +155 -153
  90. package/dist/types/src/normalization/normalization.d.ts.map +1 -0
  91. package/dist/types/src/normalization/normalization.test.d.ts.map +1 -0
  92. package/dist/types/src/normalization/utils.d.ts.map +1 -0
  93. package/dist/types/src/operations/create.d.ts +1 -1
  94. package/dist/types/src/operations/create.d.ts.map +1 -1
  95. package/dist/types/src/operations/definitions.d.ts +394 -382
  96. package/dist/types/src/operations/definitions.d.ts.map +1 -1
  97. package/dist/types/src/operations/index.d.ts +1 -1
  98. package/dist/types/src/operations/index.d.ts.map +1 -1
  99. package/dist/types/src/operations/open.d.ts +1 -1
  100. package/dist/types/src/operations/open.d.ts.map +1 -1
  101. package/dist/types/src/operations/summarize.d.ts +1 -1
  102. package/dist/types/src/operations/summarize.d.ts.map +1 -1
  103. package/dist/types/src/{components/stories → stories}/FileTranscription.stories.d.ts +3 -3
  104. package/dist/types/src/stories/FileTranscription.stories.d.ts.map +1 -0
  105. package/dist/types/src/stories/KeyWordRecognition.stories.d.ts.map +1 -0
  106. package/dist/types/src/{components/stories → stories}/MicrophoneTranscription.stories.d.ts +1 -1
  107. package/dist/types/src/stories/MicrophoneTranscription.stories.d.ts.map +1 -0
  108. package/dist/types/src/stories/TranscriptionStory.d.ts +23 -0
  109. package/dist/types/src/stories/TranscriptionStory.d.ts.map +1 -0
  110. package/dist/types/src/stories/useIsSpeaking.d.ts.map +1 -0
  111. package/dist/types/src/testing/testing.d.ts.map +1 -1
  112. package/dist/types/src/transcriber/index.d.ts +1 -1
  113. package/dist/types/src/transcriber/index.d.ts.map +1 -1
  114. package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +1 -1
  115. package/dist/types/src/transcriber/transcriber.d.ts +57 -2
  116. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  117. package/dist/types/src/transcriber/transcriber.test.d.ts +2 -0
  118. package/dist/types/src/transcriber/transcriber.test.d.ts.map +1 -0
  119. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  120. package/dist/types/src/translations.d.ts +7 -8
  121. package/dist/types/src/translations.d.ts.map +1 -1
  122. package/dist/types/src/types/capabilities.d.ts +2 -1
  123. package/dist/types/src/types/capabilities.d.ts.map +1 -1
  124. package/dist/types/src/types/{types.d.ts → defs.d.ts} +1 -1
  125. package/dist/types/src/types/defs.d.ts.map +1 -0
  126. package/dist/types/src/types/index.d.ts +1 -1
  127. package/dist/types/src/types/index.d.ts.map +1 -1
  128. package/dist/types/src/util/array.d.ts.map +1 -1
  129. package/dist/types/src/util/get-time-str.d.ts.map +1 -1
  130. package/dist/types/src/util/monitor-audio-level.d.ts.map +1 -1
  131. package/dist/types/src/util/render-byline.d.ts.map +1 -1
  132. package/dist/types/tsconfig.tsbuildinfo +1 -1
  133. package/package.json +76 -67
  134. package/src/TranscriptionPlugin.node.ts +48 -0
  135. package/src/TranscriptionPlugin.test.ts +31 -0
  136. package/src/TranscriptionPlugin.tsx +7 -3
  137. package/src/blueprints/transcription-blueprint.ts +2 -3
  138. package/src/capabilities/blueprint-definition.ts +2 -0
  139. package/src/capabilities/index.ts +2 -1
  140. package/src/capabilities/operation-handler.ts +1 -1
  141. package/src/capabilities/react-surface.tsx +4 -2
  142. package/src/capabilities/transcriber.ts +2 -0
  143. package/src/components/Transcription/Transcription.stories.tsx +3 -5
  144. package/src/containers/TranscriptionContainer/TranscriptionContainer.tsx +4 -2
  145. package/src/hooks/useTranscriber.ts +3 -1
  146. package/src/index.ts +9 -4
  147. package/src/model/model.test.ts +3 -3
  148. package/src/model/model.ts +3 -3
  149. package/src/{segments-normalization → normalization}/message-normalizer.ts +1 -5
  150. package/src/{segments-normalization → normalization}/normalization.ts +5 -5
  151. package/src/operations/create.ts +4 -2
  152. package/src/operations/definitions.ts +3 -4
  153. package/src/operations/index.ts +1 -1
  154. package/src/operations/open.ts +5 -8
  155. package/src/operations/summarize.ts +11 -7
  156. package/src/{components/stories → stories}/FileTranscription.stories.tsx +24 -5
  157. package/src/{components/stories → stories}/KeyWordRecognition.stories.tsx +30 -28
  158. package/src/{components/stories → stories}/MicrophoneTranscription.stories.tsx +3 -3
  159. package/src/stories/TranscriptionStory.tsx +93 -0
  160. package/src/transcriber/index.ts +1 -1
  161. package/src/transcriber/transcriber.test.ts +104 -0
  162. package/src/transcriber/transcriber.ts +92 -51
  163. package/src/types/capabilities.ts +6 -1
  164. package/src/types/index.ts +1 -1
  165. package/dist/lib/browser/chunk-5LWSJZTZ.mjs.map +0 -7
  166. package/dist/lib/browser/chunk-RIUSFL62.mjs.map +0 -7
  167. package/dist/lib/browser/create-IZPB7VZW.mjs.map +0 -7
  168. package/dist/lib/browser/open-SN5O5I6X.mjs +0 -29
  169. package/dist/lib/browser/open-SN5O5I6X.mjs.map +0 -7
  170. package/dist/lib/browser/summarize-5MZENAU5.mjs.map +0 -7
  171. package/dist/lib/node-esm/chunk-3GSFEN4L.mjs.map +0 -7
  172. package/dist/lib/node-esm/chunk-X74WYCCE.mjs.map +0 -7
  173. package/dist/lib/node-esm/create-TQDGXQBL.mjs.map +0 -7
  174. package/dist/lib/node-esm/open-4GAAWWKJ.mjs +0 -30
  175. package/dist/lib/node-esm/open-4GAAWWKJ.mjs.map +0 -7
  176. package/dist/lib/node-esm/summarize-RVOSRHEC.mjs.map +0 -7
  177. package/dist/types/src/components/stories/FileTranscription.stories.d.ts.map +0 -1
  178. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts.map +0 -1
  179. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts.map +0 -1
  180. package/dist/types/src/components/stories/TranscriptionStory.d.ts +0 -12
  181. package/dist/types/src/components/stories/TranscriptionStory.d.ts.map +0 -1
  182. package/dist/types/src/components/stories/useIsSpeaking.d.ts.map +0 -1
  183. package/dist/types/src/segments-normalization/index.d.ts.map +0 -1
  184. package/dist/types/src/segments-normalization/message-normalizer.d.ts.map +0 -1
  185. package/dist/types/src/segments-normalization/normalization.d.ts.map +0 -1
  186. package/dist/types/src/segments-normalization/normalization.test.d.ts.map +0 -1
  187. package/dist/types/src/segments-normalization/utils.d.ts.map +0 -1
  188. package/dist/types/src/types/types.d.ts.map +0 -1
  189. package/src/components/stories/TranscriptionStory.tsx +0 -43
  190. package/dist/lib/browser/{chunk-HOOPZ7EM.mjs.map → chunk-KAEXRX3Y.mjs.map} +0 -0
  191. package/dist/lib/node-esm/{chunk-NVM2QUMX.mjs.map → chunk-O533NBMK.mjs.map} +0 -0
  192. package/dist/types/src/{segments-normalization → normalization}/message-normalizer.d.ts +0 -0
  193. package/dist/types/src/{segments-normalization → normalization}/normalization.test.d.ts +0 -0
  194. package/dist/types/src/{segments-normalization → normalization}/utils.d.ts +0 -0
  195. package/dist/types/src/{components/stories → stories}/KeyWordRecognition.stories.d.ts +0 -0
  196. package/dist/types/src/{components/stories → stories}/useIsSpeaking.d.ts +0 -0
  197. package/src/{segments-normalization → normalization}/index.ts +1 -1
  198. /package/src/{segments-normalization → normalization}/normalization.test.ts +0 -0
  199. /package/src/{segments-normalization → normalization}/utils.ts +0 -0
  200. /package/src/{components/stories → stories}/useIsSpeaking.tsx +0 -0
  201. /package/src/types/{types.ts → defs.ts} +0 -0
@@ -1,669 +1,21 @@
1
+ import {
2
+ useAudioFile,
3
+ useAudioTrack,
4
+ useQueueModelAdapter,
5
+ useTranscriber,
6
+ useVoiceInput
7
+ } from "./chunk-NQQK7UZQ.mjs";
8
+ import "./chunk-MLRJWAQH.mjs";
1
9
  import {
2
10
  TranscriptionCapabilities
3
- } from "./chunk-5LWSJZTZ.mjs";
11
+ } from "./chunk-3L623EVL.mjs";
4
12
  import {
5
- mergeFloat64Arrays,
6
- renderByline
7
- } from "./chunk-HOOPZ7EM.mjs";
13
+ mergeFloat64Arrays
14
+ } from "./chunk-KAEXRX3Y.mjs";
8
15
  import "./chunk-J5LGTIGS.mjs";
9
16
 
10
- // src/components/Transcription/Transcription.tsx
11
- import React from "react";
12
- import { useThemeContext } from "@dxos/react-ui";
13
- import { useTextEditor } from "@dxos/react-ui-editor";
14
- import { autoScroll, createBasicExtensions, createMarkdownExtensions, createThemeExtensions, decorateMarkdown, documentSlots, preview } from "@dxos/ui-editor";
15
- import { composable, composableProps } from "@dxos/ui-theme";
16
- import { isTruthy } from "@dxos/util";
17
-
18
- // src/components/Transcription/transcription-extension.ts
19
- import { RangeSetBuilder } from "@codemirror/state";
20
- import { EditorView, GutterMarker, ViewPlugin, gutter } from "@codemirror/view";
21
- import { format } from "date-fns/format";
22
- import { intervalToDuration } from "date-fns/intervalToDuration";
23
- import { addEventListener, combine } from "@dxos/async";
24
-
25
- // src/model/model.ts
26
- import { Text } from "@codemirror/state";
27
- import { Event } from "@dxos/async";
28
- import { invariant } from "@dxos/invariant";
29
- import { log } from "@dxos/log";
30
- var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/model/model.ts";
31
- var DocumentAdapter = class {
32
- _view;
33
- constructor(_view) {
34
- this._view = _view;
35
- }
36
- /** The document must always have at least one line. */
37
- lineCount() {
38
- return this._view.state.doc.lines - 1;
39
- }
40
- replaceLines(from, remove, insert) {
41
- log("replaceLines", {
42
- count: this._view.state.doc.lines,
43
- from,
44
- remove,
45
- insert
46
- }, {
47
- F: __dxlog_file,
48
- L: 39,
49
- S: this,
50
- C: (f, a) => f(...a)
51
- });
52
- const numLines = this._view.state.doc.lines;
53
- const posFrom = this._view.state.doc.line(from).from;
54
- const posTo = remove === 0 ? posFrom : this._view.state.doc.line(Math.min(numLines, from + remove)).from;
55
- let text = insert.join("\n");
56
- if (posTo === this._view.state.doc.length) {
57
- text += "\n";
58
- }
59
- this._view.dispatch({
60
- changes: {
61
- from: posFrom,
62
- to: posTo,
63
- insert: text
64
- }
65
- });
66
- }
67
- };
68
- var SerializationModel = class {
69
- _renderer;
70
- /** Ordered set of chunks. */
71
- _chunks = [];
72
- /** Map of chunk IDs to their current line counts. */
73
- _chunkLineCounts = /* @__PURE__ */ new Map();
74
- /** Map of line numbers to chunk IDs. */
75
- _lineToChunk = /* @__PURE__ */ new Map();
76
- /** Track chunk changes since last sync. */
77
- _changes = [];
78
- /** Emits when the document is updated. */
79
- update = new Event();
80
- constructor(_renderer, initialChunks = []) {
81
- this._renderer = _renderer;
82
- initialChunks.forEach((chunk) => {
83
- this.appendChunk(chunk);
84
- });
85
- }
86
- toJSON() {
87
- return {
88
- chunks: this._chunks.length,
89
- changes: this._changes.length
90
- };
91
- }
92
- get doc() {
93
- return Text.of([
94
- ...this._chunks.flatMap((chunk, index) => this._renderer(chunk, index)),
95
- ""
96
- ]);
97
- }
98
- get chunks() {
99
- return this._chunks;
100
- }
101
- /**
102
- * Get the block ID at the given line number.
103
- */
104
- getChunkAtLine(line) {
105
- return this._lineToChunk.get(line);
106
- }
107
- reset() {
108
- this._chunks.length = 0;
109
- this._chunkLineCounts.clear();
110
- this._lineToChunk.clear();
111
- this.update.emit();
112
- return this;
113
- }
114
- appendChunk(chunk) {
115
- const index = this._chunks.length;
116
- this._chunks.push(chunk);
117
- this._changes.push({
118
- type: "append",
119
- index,
120
- chunk
121
- });
122
- this.update.emit();
123
- return this;
124
- }
125
- updateChunk(chunk) {
126
- const index = this._chunks.findIndex((c) => c.id === chunk.id);
127
- invariant(index !== -1, void 0, {
128
- F: __dxlog_file,
129
- L: 147,
130
- S: this,
131
- A: [
132
- "index !== -1",
133
- ""
134
- ]
135
- });
136
- this._chunks[index] = chunk;
137
- this._changes.push({
138
- type: "update",
139
- index,
140
- chunk
141
- });
142
- this.update.emit();
143
- return this;
144
- }
145
- deleteBlock(id) {
146
- const index = this._chunks.findIndex((c) => c.id === id);
147
- invariant(index !== -1, void 0, {
148
- F: __dxlog_file,
149
- L: 156,
150
- S: this,
151
- A: [
152
- "index !== -1",
153
- ""
154
- ]
155
- });
156
- this._chunks.splice(index, 1);
157
- this._changes.push({
158
- type: "delete",
159
- index,
160
- id
161
- });
162
- this.update.emit();
163
- return this;
164
- }
165
- /**
166
- * Syncs the tracked changes with the ChunkDocument.
167
- */
168
- sync(document2) {
169
- log("sync", {
170
- changes: this._changes
171
- }, {
172
- F: __dxlog_file,
173
- L: 167,
174
- S: this,
175
- C: (f, a) => f(...a)
176
- });
177
- for (const change of this._changes) {
178
- switch (change.type) {
179
- case "append": {
180
- const lines = this._renderer(change.chunk, change.index);
181
- const lastLine = document2.lineCount();
182
- document2.replaceLines(lastLine + 1, 0, lines);
183
- break;
184
- }
185
- case "update": {
186
- let lineStart = 1;
187
- for (let i = 0; i < change.index; i++) {
188
- lineStart += this._chunkLineCounts.get(this._chunks[i].id);
189
- }
190
- const previousLineCount = this._chunkLineCounts.get(change.chunk.id);
191
- const newLines = this._renderer(change.chunk, change.index);
192
- document2.replaceLines(lineStart, previousLineCount, newLines);
193
- break;
194
- }
195
- case "delete": {
196
- let lineStart = 1;
197
- for (let i = 0; i < change.index; i++) {
198
- lineStart += this._chunkLineCounts.get(this._chunks[i].id);
199
- }
200
- const previousLineCount = this._chunkLineCounts.get(change.id);
201
- document2.replaceLines(lineStart, previousLineCount, []);
202
- break;
203
- }
204
- }
205
- }
206
- this._lineToChunk.clear();
207
- let currentLine = 1;
208
- for (const [index, chunk] of this._chunks.entries()) {
209
- const lineCount = this._renderer(chunk, index).length;
210
- this._chunkLineCounts.set(chunk.id, lineCount);
211
- this._lineToChunk.set(currentLine, chunk);
212
- currentLine += lineCount;
213
- }
214
- const chunkIds = new Set(this._chunks.map((chunk) => chunk.id));
215
- for (const id of this._chunkLineCounts.keys()) {
216
- if (!chunkIds.has(id)) {
217
- this._chunkLineCounts.delete(id);
218
- }
219
- }
220
- this._changes.length = 0;
221
- return this;
222
- }
223
- };
224
-
225
- // src/components/Transcription/transcription-extension.ts
226
- var transcription = ({ model, started }) => {
227
- return [
228
- // Show timestamps in the gutter.
229
- gutter({
230
- class: "cm-timestamp-gutter",
231
- lineMarkerChange: (update) => update.docChanged || update.viewportChanged,
232
- markers: (view) => {
233
- const start = getStartTime(started, model.chunks[0]);
234
- const builder = new RangeSetBuilder();
235
- for (const { from, to } of view.visibleRanges) {
236
- let line = view.state.doc.lineAt(from);
237
- while (line.from <= to) {
238
- const block = model.getChunkAtLine(line.number)?.blocks[0];
239
- const timestamp = block?._tag === "transcript" && block.started;
240
- if (timestamp) {
241
- builder.add(line.from, line.from, new TimestampMarker(line.number, new Date(timestamp), start));
242
- }
243
- if (line.to + 1 > view.state.doc.length) {
244
- break;
245
- }
246
- line = view.state.doc.lineAt(line.to + 1);
247
- }
248
- }
249
- return builder.finish();
250
- }
251
- }),
252
- // Listen for model updates.
253
- ViewPlugin.fromClass(class {
254
- _controls;
255
- _cleanup;
256
- _adapter;
257
- _initialized = false;
258
- constructor(view) {
259
- this._adapter = new DocumentAdapter(view);
260
- const scroller = view.scrollDOM;
261
- let isAutoScrolling = false;
262
- let hasScrolled = false;
263
- let timeout;
264
- const scrollToBottom = (smooth = false) => {
265
- scroller.style.scrollBehavior = smooth ? "smooth" : "";
266
- scroller.classList.add("cm-hide-scrollbar");
267
- isAutoScrolling = true;
268
- clearTimeout(timeout);
269
- timeout = setTimeout(() => {
270
- this._controls?.classList.add("opacity-0");
271
- scroller.classList.remove("cm-hide-scrollbar");
272
- isAutoScrolling = false;
273
- }, 500);
274
- view.dispatch({
275
- effects: EditorView.scrollIntoView(view.state.doc.length, {
276
- y: "end"
277
- })
278
- });
279
- };
280
- this._cleanup = combine(addEventListener(view.scrollDOM, "scroll", () => {
281
- if (!isAutoScrolling) {
282
- hasScrolled = true;
283
- this._controls?.classList.remove("opacity-0");
284
- }
285
- }), model.update.on(() => {
286
- const autoScroll2 = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight === 0 || !hasScrolled;
287
- model.sync(this._adapter);
288
- if (autoScroll2) {
289
- scrollToBottom(true);
290
- }
291
- }));
292
- }
293
- update(_update) {
294
- if (!this._initialized) {
295
- this._initialized = true;
296
- setTimeout(() => {
297
- model.sync(this._adapter);
298
- });
299
- }
300
- }
301
- destroy() {
302
- this._controls?.remove();
303
- this._cleanup();
304
- }
305
- }),
306
- EditorView.theme({
307
- ".cm-gutters": {
308
- backgroundColor: "var(--color-base-surface)"
309
- },
310
- ".cm-timestamp-gutter": {
311
- width: "6rem",
312
- paddingLeft: "0.5rem",
313
- paddingRight: "1rem"
314
- },
315
- ".cm-timestamp-gutter > .cm-gutterElement > div": {
316
- display: "inline-flex",
317
- textAlign: "right",
318
- padding: "3px"
319
- }
320
- })
321
- ];
322
- };
323
- var TimestampMarker = class extends GutterMarker {
324
- _line;
325
- _timestamp;
326
- _started;
327
- constructor(_line, _timestamp, _started) {
328
- super(), this._line = _line, this._timestamp = _timestamp, this._started = _started;
329
- }
330
- eq(other) {
331
- return this._timestamp === other._timestamp;
332
- }
333
- toDOM(view) {
334
- const el = document.createElement("div");
335
- el.className = "text-sm text-subdued hover:bg-hover-surface cursor-pointer";
336
- el.textContent = formatTimestamp(this._timestamp, this._started);
337
- el.onclick = () => {
338
- const pos = view.state.doc.line(this._line).from;
339
- view.dispatch({
340
- effects: EditorView.scrollIntoView(pos, {
341
- y: "start"
342
- })
343
- });
344
- };
345
- return el;
346
- }
347
- };
348
- var getStartTime = (started, message) => {
349
- if (started) {
350
- return started;
351
- }
352
- if (message?.blocks[0]?._tag === "transcript" && message.blocks[0].started) {
353
- return new Date(message.blocks[0].started);
354
- }
355
- return void 0;
356
- };
357
- var formatTimestamp = (timestamp, relative) => {
358
- if (relative) {
359
- const pad = (n = 0) => String(n).padStart(2, "0");
360
- const { hours, minutes, seconds } = intervalToDuration({
361
- start: relative,
362
- end: timestamp
363
- });
364
- return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
365
- } else {
366
- return format(timestamp, "HH:mm:ss");
367
- }
368
- };
369
-
370
- // src/components/Transcription/Transcription.tsx
371
- var Transcription = composable(({ transcript: object, model, children, ...props }, forwardedRef) => {
372
- const { themeMode } = useThemeContext();
373
- const { parentRef } = useTextEditor(() => {
374
- return {
375
- extensions: [
376
- createBasicExtensions({
377
- readOnly: true,
378
- lineWrapping: true,
379
- search: true
380
- }),
381
- createMarkdownExtensions(),
382
- createThemeExtensions({
383
- themeMode,
384
- slots: documentSlots
385
- }),
386
- decorateMarkdown(),
387
- preview(),
388
- transcription({
389
- model,
390
- started: object?.started ? new Date(object.started) : void 0
391
- }),
392
- autoScroll()
393
- ].filter(isTruthy)
394
- };
395
- }, [
396
- model
397
- ]);
398
- return /* @__PURE__ */ React.createElement("div", {
399
- ...composableProps(props, {
400
- classNames: "dx-container"
401
- }),
402
- ref: parentRef,
403
- "data-popover-collision-boundary": true
404
- });
405
- });
406
-
407
- // src/hooks/useAudioFile.ts
408
- import { useEffect, useState } from "react";
409
- import { scheduleTask } from "@dxos/async";
410
- import { Context } from "@dxos/context";
411
- import { log as log2 } from "@dxos/log";
412
- var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useAudioFile.ts";
413
- var useAudioFile = (audioUrl, constraints) => {
414
- const [{ audio, stream, track }, setStream] = useState({});
415
- useEffect(() => {
416
- const ctx = new Context(void 0, {
417
- F: __dxlog_file2,
418
- L: 20
419
- });
420
- scheduleTask(ctx, async () => {
421
- try {
422
- const response = await fetch(audioUrl);
423
- const blob = await response.blob();
424
- const objectUrl = URL.createObjectURL(blob);
425
- ctx.onDispose(() => {
426
- URL.revokeObjectURL(objectUrl);
427
- });
428
- const audio2 = new Audio();
429
- audio2.src = objectUrl;
430
- await new Promise((resolve, reject) => {
431
- audio2.addEventListener("error", (err) => {
432
- log2.error("error", {
433
- err
434
- }, {
435
- F: __dxlog_file2,
436
- L: 39,
437
- S: void 0,
438
- C: (f, a) => f(...a)
439
- });
440
- reject(err);
441
- }, {
442
- once: true
443
- });
444
- audio2.addEventListener("canplay", async () => {
445
- resolve();
446
- }, {
447
- once: true
448
- });
449
- audio2.load();
450
- });
451
- const audioCtx = new AudioContext();
452
- if (audioCtx.state === "suspended") {
453
- await audioCtx.resume();
454
- }
455
- const destination = audioCtx.createMediaStreamDestination();
456
- destination.channelCount = 1;
457
- const source = audioCtx.createMediaElementSource(audio2);
458
- source.connect(destination);
459
- const track2 = destination.stream.getAudioTracks()[0];
460
- if (constraints) {
461
- await track2.applyConstraints(constraints).catch((err) => log2.catch(err, void 0, {
462
- F: __dxlog_file2,
463
- L: 68,
464
- S: void 0,
465
- C: (f, a) => f(...a)
466
- }));
467
- }
468
- setStream({
469
- audio: audio2,
470
- stream: destination.stream,
471
- track: destination.stream.getAudioTracks()[0]
472
- });
473
- } catch (err) {
474
- log2.catch(err, void 0, {
475
- F: __dxlog_file2,
476
- L: 78,
477
- S: void 0,
478
- C: (f, a) => f(...a)
479
- });
480
- }
481
- });
482
- return () => {
483
- void ctx.dispose();
484
- };
485
- }, [
486
- audioUrl
487
- ]);
488
- return {
489
- audio,
490
- stream,
491
- track
492
- };
493
- };
494
-
495
- // src/hooks/useAudioTrack.ts
496
- import { useEffect as useEffect2, useState as useState2 } from "react";
497
- var useAudioTrack = (active, constraints) => {
498
- const [track, setTrack] = useState2();
499
- useEffect2(() => {
500
- if (!active) {
501
- track?.stop();
502
- setTrack(void 0);
503
- return;
504
- }
505
- const initAudio = async () => {
506
- const audio = new Audio();
507
- audio.srcObject = await navigator.mediaDevices.getUserMedia({
508
- audio: constraints ?? true
509
- });
510
- const [track2] = audio.srcObject.getAudioTracks();
511
- if (track2) {
512
- setTrack(track2);
513
- }
514
- };
515
- if (active) {
516
- void initAudio();
517
- }
518
- }, [
519
- active
520
- ]);
521
- return track;
522
- };
523
-
524
- // src/hooks/useQueueModelAdapter.ts
525
- import { useEffect as useEffect3, useMemo, useState as useState3 } from "react";
526
- var useQueueModelAdapter = (renderer, queue, initialChunks = []) => {
527
- const model = useMemo(() => new SerializationModel(renderer, initialChunks), [
528
- queue
529
- ]);
530
- const [loaded, setLoaded] = useState3(false);
531
- useEffect3(() => {
532
- if (!queue) {
533
- return;
534
- }
535
- const update = () => {
536
- for (const block of queue?.objects ?? []) {
537
- model.appendChunk(block);
538
- }
539
- setLoaded(true);
540
- };
541
- let i;
542
- if (queue.isLoading) {
543
- i = setInterval(() => {
544
- if (!queue?.isLoading) {
545
- clearInterval(i);
546
- update();
547
- }
548
- }, 1e3);
549
- } else {
550
- update();
551
- }
552
- return () => clearTimeout(i);
553
- }, [
554
- model,
555
- queue
556
- ]);
557
- useEffect3(() => {
558
- if (!loaded || !queue || model.chunks.length === queue.objects.length) {
559
- return;
560
- }
561
- const chunk = queue.objects.at(-1);
562
- if (chunk) {
563
- model.appendChunk(chunk);
564
- }
565
- }, [
566
- model,
567
- loaded,
568
- queue?.objects.length
569
- ]);
570
- return model;
571
- };
572
-
573
- // src/hooks/useTranscriber.ts
574
- import { useEffect as useEffect4, useMemo as useMemo2 } from "react";
575
- import { useCapabilities } from "@dxos/app-framework/ui";
576
- import { TranscriptionCapabilities as TranscriptionCapabilities2 } from "#types";
577
- var useTranscriber = ({ audioStreamTrack, recorderConfig, transcriberConfig, onSegments }) => {
578
- const [getTranscriber] = useCapabilities(TranscriptionCapabilities2.Transcriber);
579
- const transcriber = useMemo2(() => {
580
- if (!getTranscriber || !audioStreamTrack || !onSegments) {
581
- return void 0;
582
- }
583
- return getTranscriber({
584
- audioStreamTrack,
585
- recorderConfig,
586
- transcriberConfig,
587
- onSegments
588
- });
589
- }, [
590
- getTranscriber,
591
- audioStreamTrack,
592
- recorderConfig,
593
- transcriberConfig,
594
- onSegments
595
- ]);
596
- useEffect4(() => {
597
- return () => {
598
- void transcriber?.close();
599
- };
600
- }, [
601
- transcriber
602
- ]);
603
- return transcriber;
604
- };
605
-
606
- // src/hooks/useVoiceInput.ts
607
- import { useCallback, useEffect as useEffect5, useState as useState4 } from "react";
608
- import { scheduleMicroTask } from "@dxos/async";
609
- import { Context as Context2 } from "@dxos/context";
610
- import { log as log3 } from "@dxos/log";
611
- import { useSoundEffect } from "@dxos/react-ui-sfx";
612
- var __dxlog_file3 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useVoiceInput.ts";
613
- var useVoiceInput = ({ active, onUpdate }) => {
614
- const soundStart = useSoundEffect("StartRecording");
615
- const soundStop = useSoundEffect("StopRecording");
616
- const handleSegments = useCallback(async (segments) => {
617
- const text = segments.map((str) => str.text.trim().replace(/[^\w\s]/g, "")).join(" ");
618
- onUpdate(text);
619
- }, []);
620
- const [recording, setRecording] = useState4(false);
621
- const track = useAudioTrack(active);
622
- const transcriber = useTranscriber({
623
- audioStreamTrack: track,
624
- onSegments: handleSegments
625
- });
626
- useEffect5(() => {
627
- const ctx = new Context2(void 0, {
628
- F: __dxlog_file3,
629
- L: 43
630
- });
631
- scheduleMicroTask(ctx, async () => {
632
- if (active && transcriber) {
633
- await transcriber.open();
634
- log3.info("starting...", void 0, {
635
- F: __dxlog_file3,
636
- L: 47,
637
- S: void 0,
638
- C: (f, a) => f(...a)
639
- });
640
- setRecording(true);
641
- void soundStart.play();
642
- transcriber.startChunksRecording();
643
- } else if (!active && transcriber?.isOpen) {
644
- transcriber?.stopChunksRecording();
645
- await transcriber?.close();
646
- log3.info("stopped", void 0, {
647
- F: __dxlog_file3,
648
- L: 54,
649
- S: void 0,
650
- C: (f, a) => f(...a)
651
- });
652
- setRecording(false);
653
- void soundStop.play();
654
- }
655
- });
656
- return () => {
657
- void ctx.dispose();
658
- };
659
- }, [
660
- active,
661
- transcriber
662
- ]);
663
- return {
664
- recording
665
- };
666
- };
17
+ // src/index.ts
18
+ import { Plugin } from "@dxos/app-framework";
667
19
 
668
20
  // src/meta.ts
669
21
  import { trim } from "@dxos/util";
@@ -687,16 +39,16 @@ var meta = {
687
39
  import { MediaRecorder, register } from "extendable-media-recorder";
688
40
  import { WaveFile } from "wavefile";
689
41
  import { synchronized } from "@dxos/async";
690
- import { invariant as invariant2 } from "@dxos/invariant";
691
- import { log as log4 } from "@dxos/log";
42
+ import { invariant } from "@dxos/invariant";
43
+ import { log } from "@dxos/log";
692
44
  import { trace } from "@dxos/tracing";
45
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/transcriber/media-stream-recorder.ts";
693
46
  function _ts_decorate(decorators, target, key, desc) {
694
47
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
695
48
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
696
49
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
697
50
  return c > 3 && r && Object.defineProperty(target, key, r), r;
698
51
  }
699
- var __dxlog_file4 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/transcriber/media-stream-recorder.ts";
700
52
  var initializingPromise;
701
53
  var initializeExtendableMediaRecorder = async () => {
702
54
  const { connect } = await import("extendable-media-recorder-wav-encoder");
@@ -730,14 +82,9 @@ var MediaStreamRecorder = class {
730
82
  this._onChunk = onChunk;
731
83
  }
732
84
  async start() {
733
- await (initializingPromise ??= initializeExtendableMediaRecorder()).catch((err) => log4.info("initializeExtendableMediaRecorder", {
85
+ await (initializingPromise ??= initializeExtendableMediaRecorder()).catch((err) => log.info("initializeExtendableMediaRecorder", {
734
86
  err
735
- }, {
736
- F: __dxlog_file4,
737
- L: 69,
738
- S: this,
739
- C: (f, a) => f(...a)
740
- }));
87
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 48, S: this }));
741
88
  if (!this._mediaRecorder) {
742
89
  const stream = new MediaStream([
743
90
  this._mediaStreamTrack
@@ -749,15 +96,7 @@ var MediaStreamRecorder = class {
749
96
  if (this._mediaRecorder.state === "recording") {
750
97
  return;
751
98
  }
752
- invariant2(this._onChunk, "MediaStreamRecorder: onChunk is not set", {
753
- F: __dxlog_file4,
754
- L: 80,
755
- S: this,
756
- A: [
757
- "this._onChunk",
758
- "'MediaStreamRecorder: onChunk is not set'"
759
- ]
760
- });
99
+ invariant(this._onChunk, "MediaStreamRecorder: onChunk is not set", { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 62, S: this, A: ["this._onChunk", "'MediaStreamRecorder: onChunk is not set'"] });
761
100
  this._mediaRecorder.ondataavailable = (event) => this._ondataavailable(event);
762
101
  this._mediaRecorder.start(this._config.interval);
763
102
  }
@@ -784,12 +123,7 @@ var MediaStreamRecorder = class {
784
123
  ...uint8Array
785
124
  ]));
786
125
  } else {
787
- log4.warn("MediaStreamRecorder: no header", void 0, {
788
- F: __dxlog_file4,
789
- L: 111,
790
- S: this,
791
- C: (f, a) => f(...a)
792
- });
126
+ log.warn("MediaStreamRecorder: no header", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 90, S: this });
793
127
  return;
794
128
  }
795
129
  this._onChunk({
@@ -809,16 +143,16 @@ MediaStreamRecorder = _ts_decorate([
809
143
  import { WaveFile as WaveFile2 } from "wavefile";
810
144
  import { DeferredTask, Trigger } from "@dxos/async";
811
145
  import { LifecycleState, Resource } from "@dxos/context";
812
- import { log as log5 } from "@dxos/log";
146
+ import { log as log2 } from "@dxos/log";
813
147
  import { trace as trace2 } from "@dxos/tracing";
814
148
  import { TRANSCRIPTION_URL } from "#types";
149
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/transcriber/transcriber.ts";
815
150
  function _ts_decorate2(decorators, target, key, desc) {
816
151
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
817
152
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
818
153
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
819
154
  return c > 3 && r && Object.defineProperty(target, key, r), r;
820
155
  }
821
- var __dxlog_file5 = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/transcriber/transcriber.ts";
822
156
  var Transcriber = class extends Resource {
823
157
  _audioChunks = [];
824
158
  _lastUsedTimestamp = 0;
@@ -828,44 +162,31 @@ var Transcriber = class extends Resource {
828
162
  _config;
829
163
  _recorder;
830
164
  _onSegments;
165
+ _transcribeFn;
831
166
  _recording = false;
832
167
  _transcribeTask = void 0;
833
- constructor({ config, recorder, onSegments }) {
168
+ constructor({ config, recorder, onSegments, transcribe }) {
834
169
  super();
835
170
  this._config = config;
836
171
  this._recorder = recorder;
837
172
  this._onSegments = onSegments;
173
+ this._transcribeFn = transcribe;
838
174
  }
839
175
  async _open(ctx) {
840
- log5.info("opening", void 0, {
841
- F: __dxlog_file5,
842
- L: 102,
843
- S: this,
844
- C: (f, a) => f(...a)
845
- });
176
+ log2.info("opening", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 41, S: this });
846
177
  this._recorder.setOnChunk((chunk) => this._saveAudioChunk(chunk));
847
178
  await this._recorder.start();
848
179
  this._transcribeTask = new DeferredTask(ctx, async () => this._transcribe());
849
180
  this._openTrigger.wake();
850
181
  }
851
182
  async _close() {
852
- log5.info("closing", void 0, {
853
- F: __dxlog_file5,
854
- L: 110,
855
- S: this,
856
- C: (f, a) => f(...a)
857
- });
183
+ log2.info("closing", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 48, S: this });
858
184
  this._recording = false;
859
185
  this._transcribeTask = void 0;
860
186
  await this._recorder.stop();
861
187
  }
862
188
  startChunksRecording() {
863
- log5.info("starting", void 0, {
864
- F: __dxlog_file5,
865
- L: 117,
866
- S: this,
867
- C: (f, a) => f(...a)
868
- });
189
+ log2.info("starting", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 54, S: this });
869
190
  if (this._lifecycleState !== LifecycleState.OPEN) {
870
191
  return;
871
192
  }
@@ -877,22 +198,12 @@ var Transcriber = class extends Resource {
877
198
  }
878
199
  this._recording = false;
879
200
  this._transcribeTask?.schedule();
880
- log5.info("stopped", void 0, {
881
- F: __dxlog_file5,
882
- L: 132,
883
- S: this,
884
- C: (f, a) => f(...a)
885
- });
201
+ log2.info("stopped", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 66, S: this });
886
202
  }
887
203
  _saveAudioChunk(chunk) {
888
- log5("saving audio chunk", {
204
+ log2("saving audio chunk", {
889
205
  chunk
890
- }, {
891
- F: __dxlog_file5,
892
- L: 136,
893
- S: this,
894
- C: (f, a) => f(...a)
895
- });
206
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 69, S: this });
896
207
  this._audioChunks.push(chunk);
897
208
  if (!this._recording && (!this._transcribeTask || !this._transcribeTask.scheduled) && this._audioChunks.length >= this._config.prefixBufferChunksAmount) {
898
209
  this._audioChunks = this._dropOldChunks();
@@ -901,14 +212,9 @@ var Transcriber = class extends Resource {
901
212
  }
902
213
  }
903
214
  async _transcribe() {
904
- log5("transcribing", {
215
+ log2("transcribing", {
905
216
  chunks: this._audioChunks.length
906
- }, {
907
- F: __dxlog_file5,
908
- L: 152,
909
- S: this,
910
- C: (f, a) => f(...a)
911
- });
217
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 81, S: this });
912
218
  const chunks = this._audioChunks;
913
219
  this._audioChunks = this._dropOldChunks();
914
220
  if (chunks.length === 0) {
@@ -935,54 +241,41 @@ var Transcriber = class extends Resource {
935
241
  }
936
242
  async _fetchTranscription(audio) {
937
243
  if (audio.length === 0) {
938
- this._audioChunks = [];
939
244
  throw new Error("No audio to send for transcribing");
940
245
  }
941
- const response = await fetch(`${TRANSCRIPTION_URL}/transcribe`, {
942
- method: "POST",
943
- body: JSON.stringify({
944
- audio
945
- }),
946
- headers: {
947
- "Content-Type": "application/json"
246
+ let segments;
247
+ if (this._transcribeFn) {
248
+ segments = await this._transcribeFn(audio);
249
+ } else {
250
+ const endpoint = this._config.endpoint ?? TRANSCRIPTION_URL;
251
+ const response = await fetch(`${endpoint}/transcribe`, {
252
+ method: "POST",
253
+ body: JSON.stringify({
254
+ audio
255
+ }),
256
+ headers: {
257
+ "Content-Type": "application/json"
258
+ }
259
+ });
260
+ if (!response.ok) {
261
+ throw new Error(`Transcription failed: ${response.statusText}`);
948
262
  }
949
- });
950
- if (!response.ok) {
951
- this._audioChunks = [];
952
- throw new Error(`Transcription failed: ${response.statusText}`);
263
+ ({ segments } = await response.json());
953
264
  }
954
- const { segments } = await response.json();
955
- log5.info("transcription response", {
956
- segments: segments.length,
957
- string: segments.map((segments2) => segments2.text).join(" ")
958
- }, {
959
- F: __dxlog_file5,
960
- L: 216,
961
- S: this,
962
- C: (f, a) => f(...a)
963
- });
265
+ if (!Array.isArray(segments)) {
266
+ throw new Error("Transcription response payload is invalid");
267
+ }
268
+ log2.info("transcription response", {
269
+ segments: segments.length
270
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 134, S: this });
964
271
  return segments;
965
272
  }
966
273
  _alignSegments(segments, originalChunks) {
967
- const zeroTimestamp = originalChunks.at(0).timestamp;
968
- const filteredSegments = segments.filter((segment) => zeroTimestamp + segment.end * 1e3 >= this._lastUsedTimestamp).map((segment) => {
969
- const words = segment.words.filter((word) => zeroTimestamp + word.start * 1e3 >= this._lastUsedTimestamp);
970
- return {
971
- ...segment,
972
- words,
973
- text: words.map((word) => word.word).join(""),
974
- start: words.at(0)?.start ?? segment.end
975
- };
976
- }).filter((segment) => segment.words.length > 0);
977
- if (filteredSegments.length === 0) {
978
- return [];
274
+ const result = alignWhisperSegments(segments, originalChunks, this._lastUsedTimestamp);
275
+ if (result.lastUsedTimestamp !== void 0) {
276
+ this._lastUsedTimestamp = result.lastUsedTimestamp;
979
277
  }
980
- this._lastUsedTimestamp = zeroTimestamp + filteredSegments.at(-1).end * 1e3;
981
- return filteredSegments.map((segment) => ({
982
- _tag: "transcript",
983
- started: new Date(zeroTimestamp + segment.start * 1e3).toISOString(),
984
- text: segment.text.trim()
985
- }));
278
+ return result.transcripts;
986
279
  }
987
280
  };
988
281
  _ts_decorate2([
@@ -995,6 +288,36 @@ _ts_decorate2([
995
288
  showInBrowserTimeline: true
996
289
  })
997
290
  ], Transcriber.prototype, "_fetchTranscription", null);
291
+ var alignWhisperSegments = (segments, originalChunks, lastUsedTimestamp) => {
292
+ if (originalChunks.length === 0) {
293
+ return {
294
+ transcripts: []
295
+ };
296
+ }
297
+ const zeroTimestamp = originalChunks[0].timestamp;
298
+ const filteredSegments = segments.filter((segment) => zeroTimestamp + segment.end * 1e3 >= lastUsedTimestamp).map((segment) => {
299
+ const words = segment.words.filter((word) => zeroTimestamp + word.start * 1e3 >= lastUsedTimestamp);
300
+ return {
301
+ ...segment,
302
+ words,
303
+ text: words.map((word) => word.word).join(""),
304
+ start: words.at(0)?.start ?? segment.end
305
+ };
306
+ }).filter((segment) => segment.words.length > 0);
307
+ if (filteredSegments.length === 0) {
308
+ return {
309
+ transcripts: []
310
+ };
311
+ }
312
+ return {
313
+ transcripts: filteredSegments.map((segment) => ({
314
+ _tag: "transcript",
315
+ started: new Date(zeroTimestamp + segment.start * 1e3).toISOString(),
316
+ text: segment.text.trim()
317
+ })),
318
+ lastUsedTimestamp: zeroTimestamp + filteredSegments.at(-1).end * 1e3
319
+ };
320
+ };
998
321
 
999
322
  // src/transcriber/transcription-manager.ts
1000
323
  import { Atom } from "@effect-atom/atom-react";
@@ -1131,77 +454,16 @@ _ts_decorate3([
1131
454
  synchronized2
1132
455
  ], TranscriptionManager.prototype, "setAudioTrack", null);
1133
456
 
1134
- // src/TranscriptionPlugin.tsx
1135
- import * as Option from "effect/Option";
1136
- import { Plugin } from "@dxos/app-framework";
1137
- import { AppActivationEvents, AppPlugin } from "@dxos/app-toolkit";
1138
- import { Annotation, Obj as Obj2 } from "@dxos/echo";
1139
- import { getSpace } from "@dxos/react-client/echo";
1140
- import { Message as Message2, Transcript } from "@dxos/types";
1141
- import { BlueprintDefinition, OperationHandler, ReactSurface, Transcriber as Transcriber2 } from "#capabilities";
1142
- import { meta as meta3 } from "#meta";
1143
-
1144
- // src/translations.ts
1145
- import { meta as meta2 } from "#meta";
1146
- var translations = [
1147
- {
1148
- "en-US": {
1149
- [meta2.id]: {
1150
- "plugin.name": "Transcription",
1151
- "transcript-companion.label": "Transcript",
1152
- "delete.button": "Delete",
1153
- "bookmark.button": "Bookmark",
1154
- "scroll-to-end.label": "Scroll to latest",
1155
- "settings.entity-extraction.label": "Entity extraction"
1156
- }
1157
- }
1158
- }
1159
- ];
1160
-
1161
- // src/TranscriptionPlugin.tsx
1162
- var TranscriptionPlugin = Plugin.define(meta3).pipe(AppPlugin.addBlueprintDefinitionModule({
1163
- activate: BlueprintDefinition
1164
- }), AppPlugin.addMetadataModule({
1165
- metadata: {
1166
- id: Transcript.Transcript.typename,
1167
- metadata: {
1168
- icon: Annotation.IconAnnotation.get(Transcript.Transcript).pipe(Option.getOrThrow).icon,
1169
- iconHue: Annotation.IconAnnotation.get(Transcript.Transcript).pipe(Option.getOrThrow).hue ?? "white",
1170
- // TODO(wittjosiah): Factor out. Artifact? Separate capability?
1171
- getTextContent: async (transcript) => {
1172
- const space = getSpace(transcript);
1173
- const members = space?.members.get().map((member) => member.identity) ?? [];
1174
- const queue = space?.queues.get(transcript.queue.dxn);
1175
- await queue?.refresh();
1176
- const content = queue?.objects.filter((message) => Obj2.instanceOf(Message2.Message, message)).flatMap((message, index) => renderByline(members)(message, index)).join("\n\n");
1177
- return content;
1178
- }
1179
- }
1180
- }
1181
- }), AppPlugin.addOperationHandlerModule({
1182
- activate: OperationHandler
1183
- }), AppPlugin.addSchemaModule({
1184
- schema: [
1185
- Transcript.Transcript
1186
- ]
1187
- }), AppPlugin.addSurfaceModule({
1188
- activate: ReactSurface
1189
- }), AppPlugin.addTranslationsModule({
1190
- translations
1191
- }), Plugin.addModule({
1192
- id: "transcription",
1193
- activatesOn: AppActivationEvents.SetupAppGraph,
1194
- activate: Transcriber2
1195
- }), Plugin.make);
457
+ // src/index.ts
458
+ var TranscriptionPlugin = Plugin.lazy(meta, () => import("#plugin"));
1196
459
  export {
1197
460
  MediaStreamRecorder,
1198
461
  Transcriber,
1199
- Transcription,
1200
462
  TranscriptionCapabilities,
1201
463
  TranscriptionManager,
1202
464
  TranscriptionPlugin,
465
+ alignWhisperSegments,
1203
466
  meta,
1204
- renderByline,
1205
467
  useAudioFile,
1206
468
  useAudioTrack,
1207
469
  useQueueModelAdapter,