@dxos/plugin-transcription 0.8.4-main.fd6878d → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (367) hide show
  1. package/LICENSE +102 -5
  2. package/PLUGIN.mdl +401 -0
  3. package/README.md +1 -1
  4. package/dist/lib/neutral/TranscriptionArticle-L6XANBH5.mjs +54 -0
  5. package/dist/lib/neutral/TranscriptionArticle-L6XANBH5.mjs.map +7 -0
  6. package/dist/lib/neutral/TranscriptionPlugin.mjs +46 -0
  7. package/dist/lib/neutral/TranscriptionPlugin.mjs.map +7 -0
  8. package/dist/lib/neutral/TranscriptionPlugin.node.mjs +25 -0
  9. package/dist/lib/neutral/TranscriptionPlugin.node.mjs.map +7 -0
  10. package/dist/lib/neutral/TranscriptionPlugin.workerd.mjs +21 -0
  11. package/dist/lib/neutral/TranscriptionPlugin.workerd.mjs.map +7 -0
  12. package/dist/lib/neutral/blueprint-definition-DA4QFRYJ.mjs +15 -0
  13. package/dist/lib/neutral/blueprint-definition-DA4QFRYJ.mjs.map +7 -0
  14. package/dist/lib/neutral/blueprints/index.mjs +8 -0
  15. package/dist/lib/neutral/capabilities/index.mjs +17 -0
  16. package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
  17. package/dist/lib/neutral/chunk-FHNI26QW.mjs +45 -0
  18. package/dist/lib/neutral/chunk-FHNI26QW.mjs.map +7 -0
  19. package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
  20. package/dist/lib/neutral/chunk-KAEXRX3Y.mjs +35 -0
  21. package/dist/lib/neutral/chunk-KAEXRX3Y.mjs.map +7 -0
  22. package/dist/lib/neutral/chunk-KMT3BMMQ.mjs +124 -0
  23. package/dist/lib/neutral/chunk-KMT3BMMQ.mjs.map +7 -0
  24. package/dist/lib/neutral/chunk-KXJZEYS7.mjs +8 -0
  25. package/dist/lib/neutral/chunk-KXJZEYS7.mjs.map +7 -0
  26. package/dist/lib/neutral/chunk-MLRJWAQH.mjs +179 -0
  27. package/dist/lib/neutral/chunk-MLRJWAQH.mjs.map +7 -0
  28. package/dist/lib/neutral/chunk-TO77KAQK.mjs +298 -0
  29. package/dist/lib/neutral/chunk-TO77KAQK.mjs.map +7 -0
  30. package/dist/lib/{browser/chunk-KJIQQHJB.mjs → neutral/chunk-TX3NQISZ.mjs} +115 -186
  31. package/dist/lib/neutral/chunk-TX3NQISZ.mjs.map +7 -0
  32. package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs +30 -0
  33. package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs.map +7 -0
  34. package/dist/lib/neutral/components/index.mjs +269 -0
  35. package/dist/lib/neutral/components/index.mjs.map +7 -0
  36. package/dist/lib/neutral/containers/index.mjs +9 -0
  37. package/dist/lib/neutral/containers/index.mjs.map +7 -0
  38. package/dist/lib/neutral/create-RVR7VC33.mjs +21 -0
  39. package/dist/lib/neutral/create-RVR7VC33.mjs.map +7 -0
  40. package/dist/lib/neutral/hooks/index.mjs +19 -0
  41. package/dist/lib/neutral/index.mjs +44 -0
  42. package/dist/lib/neutral/meta.json +1 -0
  43. package/dist/lib/neutral/meta.mjs +8 -0
  44. package/dist/lib/neutral/meta.mjs.map +7 -0
  45. package/dist/lib/neutral/open-A5KXKRH4.mjs +27 -0
  46. package/dist/lib/neutral/open-A5KXKRH4.mjs.map +7 -0
  47. package/dist/lib/neutral/operation-handler-NXMOAXFP.mjs +13 -0
  48. package/dist/lib/neutral/operation-handler-NXMOAXFP.mjs.map +7 -0
  49. package/dist/lib/neutral/operations/index.mjs +8 -0
  50. package/dist/lib/neutral/operations/index.mjs.map +7 -0
  51. package/dist/lib/neutral/plugin.mjs +16 -0
  52. package/dist/lib/neutral/plugin.mjs.map +7 -0
  53. package/dist/lib/neutral/react-surface-YMZRO242.mjs +26 -0
  54. package/dist/lib/neutral/react-surface-YMZRO242.mjs.map +7 -0
  55. package/dist/lib/neutral/summarize-5XPPMVTE.mjs +77 -0
  56. package/dist/lib/neutral/summarize-5XPPMVTE.mjs.map +7 -0
  57. package/dist/lib/neutral/text-content-KBB37HSM.mjs +30 -0
  58. package/dist/lib/neutral/text-content-KBB37HSM.mjs.map +7 -0
  59. package/dist/lib/neutral/transcriber-OGSF3XO5.mjs +59 -0
  60. package/dist/lib/neutral/transcriber-OGSF3XO5.mjs.map +7 -0
  61. package/dist/lib/neutral/translations.mjs +24 -0
  62. package/dist/lib/neutral/translations.mjs.map +7 -0
  63. package/dist/lib/neutral/types/index.mjs +10 -0
  64. package/dist/lib/neutral/types/index.mjs.map +7 -0
  65. package/dist/types/src/TranscriptionPlugin.d.ts +3 -1
  66. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  67. package/dist/types/src/TranscriptionPlugin.node.d.ts +4 -0
  68. package/dist/types/src/TranscriptionPlugin.node.d.ts.map +1 -0
  69. package/dist/types/src/TranscriptionPlugin.test.d.ts +2 -0
  70. package/dist/types/src/TranscriptionPlugin.test.d.ts.map +1 -0
  71. package/dist/types/src/TranscriptionPlugin.workerd.d.ts +4 -0
  72. package/dist/types/src/TranscriptionPlugin.workerd.d.ts.map +1 -0
  73. package/dist/types/src/blueprints/index.d.ts +2 -0
  74. package/dist/types/src/blueprints/index.d.ts.map +1 -0
  75. package/dist/types/src/blueprints/transcription-blueprint.d.ts +4 -0
  76. package/dist/types/src/blueprints/transcription-blueprint.d.ts.map +1 -0
  77. package/dist/types/src/capabilities/blueprint-definition.d.ts +6 -0
  78. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
  79. package/dist/types/src/capabilities/index.d.ts +11 -4
  80. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  81. package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
  82. package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
  83. package/dist/types/src/capabilities/react-surface.d.ts +3 -2
  84. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  85. package/dist/types/src/capabilities/text-content.d.ts +8 -0
  86. package/dist/types/src/capabilities/text-content.d.ts.map +1 -0
  87. package/dist/types/src/capabilities/transcriber.d.ts +4 -3
  88. package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
  89. package/dist/types/src/components/Oracle/Oracle.d.ts +24 -0
  90. package/dist/types/src/components/Oracle/Oracle.d.ts.map +1 -0
  91. package/dist/types/src/components/Oracle/Oracle.stories.d.ts +32 -0
  92. package/dist/types/src/components/Oracle/Oracle.stories.d.ts.map +1 -0
  93. package/dist/types/src/components/Oracle/index.d.ts +2 -0
  94. package/dist/types/src/components/Oracle/index.d.ts.map +1 -0
  95. package/dist/types/src/components/Transcription/Transcription.d.ts +11 -0
  96. package/dist/types/src/components/Transcription/Transcription.d.ts.map +1 -0
  97. package/dist/types/src/components/Transcription/Transcription.stories.d.ts +37 -0
  98. package/dist/types/src/components/Transcription/Transcription.stories.d.ts.map +1 -0
  99. package/dist/types/src/components/Transcription/index.d.ts +2 -0
  100. package/dist/types/src/components/Transcription/index.d.ts.map +1 -0
  101. package/dist/types/src/components/Transcription/transcription-extension.d.ts +15 -0
  102. package/dist/types/src/components/Transcription/transcription-extension.d.ts.map +1 -0
  103. package/dist/types/src/components/index.d.ts +2 -3
  104. package/dist/types/src/components/index.d.ts.map +1 -1
  105. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts +6 -0
  106. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts.map +1 -0
  107. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts +28 -0
  108. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts.map +1 -0
  109. package/dist/types/src/containers/TranscriptionArticle/index.d.ts +2 -0
  110. package/dist/types/src/containers/TranscriptionArticle/index.d.ts.map +1 -0
  111. package/dist/types/src/containers/index.d.ts +3 -0
  112. package/dist/types/src/containers/index.d.ts.map +1 -0
  113. package/dist/types/src/enrichment/conversation.test.d.ts +2 -0
  114. package/dist/types/src/enrichment/conversation.test.d.ts.map +1 -0
  115. package/dist/types/src/enrichment/operations.d.ts +200 -0
  116. package/dist/types/src/enrichment/operations.d.ts.map +1 -0
  117. package/dist/types/src/enrichment/parser.d.ts +26 -0
  118. package/dist/types/src/enrichment/parser.d.ts.map +1 -0
  119. package/dist/types/src/enrichment/stream-simulator.d.ts +38 -0
  120. package/dist/types/src/enrichment/stream-simulator.d.ts.map +1 -0
  121. package/dist/types/src/hooks/index.d.ts +2 -1
  122. package/dist/types/src/hooks/index.d.ts.map +1 -1
  123. package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
  124. package/dist/types/src/hooks/useAudioTrack.d.ts.map +1 -1
  125. package/dist/types/src/hooks/useFeedModelAdapter.d.ts +12 -0
  126. package/dist/types/src/hooks/useFeedModelAdapter.d.ts.map +1 -0
  127. package/dist/types/src/hooks/useTranscriber.d.ts +2 -2
  128. package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
  129. package/dist/types/src/hooks/useTranscriptionRecording.d.ts +12 -0
  130. package/dist/types/src/hooks/useTranscriptionRecording.d.ts.map +1 -0
  131. package/dist/types/src/hooks/useVoiceInput.d.ts.map +1 -1
  132. package/dist/types/src/index.d.ts +2 -3
  133. package/dist/types/src/index.d.ts.map +1 -1
  134. package/dist/types/src/meta.d.ts +2 -3
  135. package/dist/types/src/meta.d.ts.map +1 -1
  136. package/dist/types/src/model/model.d.ts +2 -2
  137. package/dist/types/src/model/model.d.ts.map +1 -1
  138. package/dist/types/src/{segments-normalization → normalization}/index.d.ts +1 -1
  139. package/dist/types/src/normalization/index.d.ts.map +1 -0
  140. package/dist/types/src/{segments-normalization → normalization}/message-normalizer.d.ts +9 -7
  141. package/dist/types/src/normalization/message-normalizer.d.ts.map +1 -0
  142. package/dist/types/src/normalization/normalization.d.ts +834 -0
  143. package/dist/types/src/normalization/normalization.d.ts.map +1 -0
  144. package/dist/types/src/normalization/normalization.test.d.ts.map +1 -0
  145. package/dist/types/src/normalization/utils.d.ts +3 -0
  146. package/dist/types/src/normalization/utils.d.ts.map +1 -0
  147. package/dist/types/src/operations/create.d.ts +5 -0
  148. package/dist/types/src/operations/create.d.ts.map +1 -0
  149. package/dist/types/src/operations/index.d.ts +3 -0
  150. package/dist/types/src/operations/index.d.ts.map +1 -0
  151. package/dist/types/src/operations/open.d.ts +5 -0
  152. package/dist/types/src/operations/open.d.ts.map +1 -0
  153. package/dist/types/src/operations/summarize.d.ts +8 -0
  154. package/dist/types/src/operations/summarize.d.ts.map +1 -0
  155. package/dist/types/src/plugin.d.ts +4 -0
  156. package/dist/types/src/plugin.d.ts.map +1 -0
  157. package/dist/types/src/stories/FileTranscription.stories.d.ts +20 -0
  158. package/dist/types/src/stories/FileTranscription.stories.d.ts.map +1 -0
  159. package/dist/types/src/stories/KeyWordRecognition.stories.d.ts +14 -0
  160. package/dist/types/src/stories/KeyWordRecognition.stories.d.ts.map +1 -0
  161. package/dist/types/src/stories/LiveTranscription.stories.d.ts +20 -0
  162. package/dist/types/src/stories/LiveTranscription.stories.d.ts.map +1 -0
  163. package/dist/types/src/stories/TranscriptionStory.d.ts +21 -0
  164. package/dist/types/src/stories/TranscriptionStory.d.ts.map +1 -0
  165. package/dist/types/src/stories/common.d.ts +248 -0
  166. package/dist/types/src/stories/common.d.ts.map +1 -0
  167. package/dist/types/src/testing/testing.d.ts +14 -15
  168. package/dist/types/src/testing/testing.d.ts.map +1 -1
  169. package/dist/types/src/transcriber/index.d.ts +1 -1
  170. package/dist/types/src/transcriber/index.d.ts.map +1 -1
  171. package/dist/types/src/transcriber/media-stream-recorder.d.ts +2 -2
  172. package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +1 -1
  173. package/dist/types/src/transcriber/transcriber.d.ts +61 -6
  174. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  175. package/dist/types/src/transcriber/transcriber.test.d.ts +2 -0
  176. package/dist/types/src/transcriber/transcriber.test.d.ts.map +1 -0
  177. package/dist/types/src/transcriber/transcription-manager.d.ts +17 -16
  178. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  179. package/dist/types/src/translations.d.ts +9 -8
  180. package/dist/types/src/translations.d.ts.map +1 -1
  181. package/dist/types/src/types/TranscriptOperation.d.ts +1670 -0
  182. package/dist/types/src/types/TranscriptOperation.d.ts.map +1 -0
  183. package/dist/types/src/types/TranscriptionCapabilities.d.ts +17 -0
  184. package/dist/types/src/types/TranscriptionCapabilities.d.ts.map +1 -0
  185. package/dist/types/src/types/index.d.ts +2 -2
  186. package/dist/types/src/types/index.d.ts.map +1 -1
  187. package/dist/types/src/util/array.d.ts.map +1 -1
  188. package/dist/types/src/util/get-time-str.d.ts.map +1 -1
  189. package/dist/types/src/util/index.d.ts +1 -0
  190. package/dist/types/src/util/index.d.ts.map +1 -1
  191. package/dist/types/src/util/monitor-audio-level.d.ts.map +1 -1
  192. package/dist/types/src/util/render-byline.d.ts +4 -0
  193. package/dist/types/src/util/render-byline.d.ts.map +1 -0
  194. package/dist/types/tsconfig.tsbuildinfo +1 -1
  195. package/package.json +153 -85
  196. package/src/TranscriptionPlugin.node.ts +20 -0
  197. package/src/TranscriptionPlugin.test.ts +31 -0
  198. package/src/TranscriptionPlugin.tsx +28 -61
  199. package/src/TranscriptionPlugin.workerd.ts +18 -0
  200. package/src/blueprints/index.ts +5 -0
  201. package/src/blueprints/transcription-blueprint.ts +29 -0
  202. package/src/capabilities/blueprint-definition.ts +19 -0
  203. package/src/capabilities/index.ts +16 -6
  204. package/src/capabilities/operation-handler.ts +16 -0
  205. package/src/capabilities/react-surface.tsx +23 -14
  206. package/src/capabilities/text-content.ts +33 -0
  207. package/src/capabilities/transcriber.ts +54 -41
  208. package/src/components/Oracle/Oracle.stories.tsx +147 -0
  209. package/src/components/Oracle/Oracle.tsx +142 -0
  210. package/src/components/Oracle/index.ts +5 -0
  211. package/src/components/Transcription/Transcription.stories.tsx +213 -0
  212. package/src/components/Transcription/Transcription.tsx +55 -0
  213. package/src/components/{Transcript → Transcription}/index.ts +1 -1
  214. package/src/components/{Transcript/transcript-extension.ts → Transcription/transcription-extension.ts} +13 -46
  215. package/src/components/index.ts +2 -6
  216. package/src/containers/TranscriptionArticle/TranscriptionArticle.stories.tsx +61 -0
  217. package/src/containers/TranscriptionArticle/TranscriptionArticle.tsx +62 -0
  218. package/src/containers/TranscriptionArticle/index.ts +5 -0
  219. package/src/containers/index.ts +7 -0
  220. package/src/enrichment/conversation.test.ts +162 -0
  221. package/src/enrichment/conversation.txt +23 -0
  222. package/src/enrichment/operations.ts +271 -0
  223. package/src/enrichment/parser.ts +101 -0
  224. package/src/enrichment/stream-simulator.ts +125 -0
  225. package/src/hooks/index.ts +2 -1
  226. package/src/hooks/useAudioFile.ts +49 -53
  227. package/src/hooks/useAudioTrack.ts +1 -1
  228. package/src/hooks/useFeedModelAdapter.ts +46 -0
  229. package/src/hooks/useTranscriber.ts +15 -7
  230. package/src/hooks/useTranscriptionRecording.ts +87 -0
  231. package/src/hooks/useVoiceInput.ts +3 -4
  232. package/src/index.ts +4 -5
  233. package/src/meta.ts +32 -7
  234. package/src/model/model.test.ts +22 -16
  235. package/src/model/model.ts +3 -3
  236. package/src/{segments-normalization → normalization}/message-normalizer.ts +37 -24
  237. package/src/{segments-normalization → normalization}/normalization.test.ts +9 -48
  238. package/src/normalization/normalization.ts +76 -0
  239. package/src/{segments-normalization → normalization}/utils.ts +2 -2
  240. package/src/operations/create.ts +24 -0
  241. package/src/operations/index.ts +11 -0
  242. package/src/operations/open.ts +28 -0
  243. package/src/operations/summarize.ts +102 -0
  244. package/src/plugin.ts +11 -0
  245. package/src/stories/FileTranscription.stories.tsx +143 -0
  246. package/src/{components/stories → stories}/KeyWordRecognition.stories.tsx +50 -46
  247. package/src/stories/LiveTranscription.stories.tsx +153 -0
  248. package/src/stories/TranscriptionStory.tsx +101 -0
  249. package/src/stories/common.ts +233 -0
  250. package/src/testing/testing.ts +53 -65
  251. package/src/transcriber/index.ts +1 -1
  252. package/src/transcriber/media-stream-recorder.ts +3 -3
  253. package/src/transcriber/transcriber.browser.test.ts +4 -5
  254. package/src/transcriber/transcriber.test.ts +104 -0
  255. package/src/transcriber/transcriber.ts +105 -60
  256. package/src/transcriber/transcription-manager.ts +49 -59
  257. package/src/translations.ts +10 -7
  258. package/src/types/TranscriptOperation.ts +106 -0
  259. package/src/types/TranscriptionCapabilities.ts +39 -0
  260. package/src/types/index.ts +2 -2
  261. package/src/util/index.ts +1 -0
  262. package/src/util/render-byline.ts +33 -0
  263. package/src/vite-env.d.ts +10 -0
  264. package/dist/lib/browser/TranscriptContainer-FH7VAWYA.mjs +0 -11
  265. package/dist/lib/browser/chunk-5WH45KBY.mjs +0 -19
  266. package/dist/lib/browser/chunk-5WH45KBY.mjs.map +0 -7
  267. package/dist/lib/browser/chunk-BJWYA2BU.mjs +0 -782
  268. package/dist/lib/browser/chunk-BJWYA2BU.mjs.map +0 -7
  269. package/dist/lib/browser/chunk-KJIQQHJB.mjs.map +0 -7
  270. package/dist/lib/browser/chunk-KWOOVS5G.mjs +0 -55
  271. package/dist/lib/browser/chunk-KWOOVS5G.mjs.map +0 -7
  272. package/dist/lib/browser/chunk-SREIAQSP.mjs +0 -16
  273. package/dist/lib/browser/chunk-SREIAQSP.mjs.map +0 -7
  274. package/dist/lib/browser/chunk-UKUSJTQW.mjs +0 -8
  275. package/dist/lib/browser/chunk-UKUSJTQW.mjs.map +0 -7
  276. package/dist/lib/browser/index.mjs +0 -125
  277. package/dist/lib/browser/index.mjs.map +0 -7
  278. package/dist/lib/browser/intent-resolver-AOVQ7JI4.mjs +0 -30
  279. package/dist/lib/browser/intent-resolver-AOVQ7JI4.mjs.map +0 -7
  280. package/dist/lib/browser/meta.json +0 -1
  281. package/dist/lib/browser/react-surface-4MEJMKYQ.mjs +0 -34
  282. package/dist/lib/browser/react-surface-4MEJMKYQ.mjs.map +0 -7
  283. package/dist/lib/browser/transcriber-V77CN7XX.mjs +0 -56
  284. package/dist/lib/browser/transcriber-V77CN7XX.mjs.map +0 -7
  285. package/dist/lib/browser/types/index.mjs +0 -14
  286. package/dist/lib/node-esm/TranscriptContainer-GEUOOYHX.mjs +0 -12
  287. package/dist/lib/node-esm/chunk-A33GNR44.mjs +0 -507
  288. package/dist/lib/node-esm/chunk-A33GNR44.mjs.map +0 -7
  289. package/dist/lib/node-esm/chunk-IKQMDRY6.mjs +0 -56
  290. package/dist/lib/node-esm/chunk-IKQMDRY6.mjs.map +0 -7
  291. package/dist/lib/node-esm/chunk-PHP7MCAY.mjs +0 -10
  292. package/dist/lib/node-esm/chunk-PHP7MCAY.mjs.map +0 -7
  293. package/dist/lib/node-esm/chunk-TM2ASOZA.mjs +0 -17
  294. package/dist/lib/node-esm/chunk-TM2ASOZA.mjs.map +0 -7
  295. package/dist/lib/node-esm/chunk-XMUCZBP3.mjs +0 -21
  296. package/dist/lib/node-esm/chunk-XMUCZBP3.mjs.map +0 -7
  297. package/dist/lib/node-esm/chunk-Y7PCJ34K.mjs +0 -783
  298. package/dist/lib/node-esm/chunk-Y7PCJ34K.mjs.map +0 -7
  299. package/dist/lib/node-esm/index.mjs +0 -126
  300. package/dist/lib/node-esm/index.mjs.map +0 -7
  301. package/dist/lib/node-esm/intent-resolver-P4XPIKQF.mjs +0 -31
  302. package/dist/lib/node-esm/intent-resolver-P4XPIKQF.mjs.map +0 -7
  303. package/dist/lib/node-esm/meta.json +0 -1
  304. package/dist/lib/node-esm/react-surface-EZUPNHUC.mjs +0 -35
  305. package/dist/lib/node-esm/react-surface-EZUPNHUC.mjs.map +0 -7
  306. package/dist/lib/node-esm/transcriber-3SX3DNLV.mjs +0 -57
  307. package/dist/lib/node-esm/transcriber-3SX3DNLV.mjs.map +0 -7
  308. package/dist/lib/node-esm/types/index.mjs +0 -15
  309. package/dist/types/src/capabilities/capabilities.d.ts +0 -17
  310. package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
  311. package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
  312. package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
  313. package/dist/types/src/components/Transcript/Transcript.d.ts +0 -20
  314. package/dist/types/src/components/Transcript/Transcript.d.ts.map +0 -1
  315. package/dist/types/src/components/Transcript/Transcript.stories.d.ts +0 -24
  316. package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +0 -1
  317. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +0 -28
  318. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +0 -1
  319. package/dist/types/src/components/Transcript/index.d.ts +0 -2
  320. package/dist/types/src/components/Transcript/index.d.ts.map +0 -1
  321. package/dist/types/src/components/Transcript/transcript-extension.d.ts +0 -19
  322. package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +0 -1
  323. package/dist/types/src/components/TranscriptContainer.d.ts +0 -9
  324. package/dist/types/src/components/TranscriptContainer.d.ts.map +0 -1
  325. package/dist/types/src/components/stories/FileTranscription.stories.d.ts +0 -17
  326. package/dist/types/src/components/stories/FileTranscription.stories.d.ts.map +0 -1
  327. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts +0 -10
  328. package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts.map +0 -1
  329. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts +0 -19
  330. package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts.map +0 -1
  331. package/dist/types/src/components/stories/TranscriptionStory.d.ts +0 -11
  332. package/dist/types/src/components/stories/TranscriptionStory.d.ts.map +0 -1
  333. package/dist/types/src/components/stories/useIsSpeaking.d.ts +0 -3
  334. package/dist/types/src/components/stories/useIsSpeaking.d.ts.map +0 -1
  335. package/dist/types/src/hooks/useQueueModelAdapter.d.ts +0 -8
  336. package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +0 -1
  337. package/dist/types/src/segments-normalization/index.d.ts.map +0 -1
  338. package/dist/types/src/segments-normalization/message-normalizer.d.ts.map +0 -1
  339. package/dist/types/src/segments-normalization/normalization.d.ts +0 -422
  340. package/dist/types/src/segments-normalization/normalization.d.ts.map +0 -1
  341. package/dist/types/src/segments-normalization/normalization.test.d.ts.map +0 -1
  342. package/dist/types/src/segments-normalization/utils.d.ts +0 -3
  343. package/dist/types/src/segments-normalization/utils.d.ts.map +0 -1
  344. package/dist/types/src/types/schema.d.ts +0 -41
  345. package/dist/types/src/types/schema.d.ts.map +0 -1
  346. package/dist/types/src/types/types.d.ts +0 -31
  347. package/dist/types/src/types/types.d.ts.map +0 -1
  348. package/src/capabilities/capabilities.ts +0 -33
  349. package/src/capabilities/intent-resolver.ts +0 -24
  350. package/src/components/Transcript/Transcript.stories.tsx +0 -243
  351. package/src/components/Transcript/Transcript.tsx +0 -101
  352. package/src/components/Transcript/deprecated/OldTranscript.tsx +0 -260
  353. package/src/components/TranscriptContainer.tsx +0 -36
  354. package/src/components/stories/FileTranscription.stories.tsx +0 -246
  355. package/src/components/stories/MicrophoneTranscription.stories.tsx +0 -283
  356. package/src/components/stories/TranscriptionStory.tsx +0 -41
  357. package/src/components/stories/useIsSpeaking.tsx +0 -40
  358. package/src/hooks/useQueueModelAdapter.ts +0 -66
  359. package/src/segments-normalization/normalization.ts +0 -115
  360. package/src/types/schema.ts +0 -41
  361. package/src/types/types.ts +0 -33
  362. package/dist/lib/{browser/types → neutral/blueprints}/index.mjs.map +0 -0
  363. package/dist/lib/{browser/TranscriptContainer-FH7VAWYA.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
  364. package/dist/lib/{node-esm/types → neutral/hooks}/index.mjs.map +0 -0
  365. package/dist/lib/{node-esm/TranscriptContainer-GEUOOYHX.mjs.map → neutral/index.mjs.map} +0 -0
  366. package/dist/types/src/{segments-normalization → normalization}/normalization.test.d.ts +0 -0
  367. package/src/{segments-normalization → normalization}/index.ts +1 -1
@@ -0,0 +1,104 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ import { describe, test } from 'vitest';
6
+
7
+ import { type AudioChunk } from './audio-recorder';
8
+ import { alignWhisperSegments, type WhisperSegment } from './transcriber';
9
+
10
+ const T0 = Date.parse('2026-01-01T00:00:00.000Z');
11
+
12
+ const chunk = (offsetMs = 0, samples = 16): AudioChunk => ({
13
+ timestamp: T0 + offsetMs,
14
+ data: new Float64Array(samples),
15
+ });
16
+
17
+ const segment = (overrides: Partial<WhisperSegment>): WhisperSegment => ({
18
+ text: '',
19
+ start: 0,
20
+ end: 0,
21
+ no_speech_prob: 0,
22
+ words: [],
23
+ ...overrides,
24
+ });
25
+
26
+ describe('alignWhisperSegments', () => {
27
+ test('returns empty when no chunks were transcribed', ({ expect }) => {
28
+ const result = alignWhisperSegments(
29
+ [segment({ text: 'x', end: 1, words: [{ word: 'x', start: 0, end: 1 }] })],
30
+ [],
31
+ 0,
32
+ );
33
+ expect(result.transcripts).toEqual([]);
34
+ expect(result.lastTimestamp).toBeUndefined();
35
+ });
36
+
37
+ test('absolute-timestamps and deduplicates segments against lastTimestamp', ({ expect }) => {
38
+ const segments: WhisperSegment[] = [
39
+ segment({
40
+ text: 'hello world',
41
+ start: 0,
42
+ end: 1,
43
+ words: [
44
+ { word: 'hello ', start: 0, end: 0.5 },
45
+ { word: 'world', start: 0.5, end: 1 },
46
+ ],
47
+ }),
48
+ ];
49
+
50
+ const first = alignWhisperSegments(segments, [chunk(0)], 0);
51
+ expect(first.transcripts).toHaveLength(1);
52
+ expect(first.transcripts[0]._tag).toBe('transcript');
53
+ expect(first.transcripts[0].text).toBe('hello world');
54
+ expect(new Date(first.transcripts[0].started).getTime()).toBe(T0);
55
+ expect(first.lastTimestamp).toBe(T0 + 1_000);
56
+
57
+ // Same segments, same chunk start: every word's absolute start is < lastTimestamp -> filtered out.
58
+ const second = alignWhisperSegments(segments, [chunk(0)], first.lastTimestamp!);
59
+ expect(second.transcripts).toEqual([]);
60
+ expect(second.lastTimestamp).toBeUndefined();
61
+ });
62
+
63
+ test('keeps later words when earlier words fall before lastTimestamp', ({ expect }) => {
64
+ const segments: WhisperSegment[] = [
65
+ segment({
66
+ text: 'old new',
67
+ start: 0,
68
+ end: 2,
69
+ words: [
70
+ { word: 'old ', start: 0, end: 1 },
71
+ { word: 'new', start: 1.5, end: 2 },
72
+ ],
73
+ }),
74
+ ];
75
+
76
+ // First word starts at T0, second at T0+1500 — only the second survives a cursor at T0+1000.
77
+ const result = alignWhisperSegments(segments, [chunk(0)], T0 + 1_000);
78
+ expect(result.transcripts).toHaveLength(1);
79
+ expect(result.transcripts[0].text).toBe('new');
80
+ expect(new Date(result.transcripts[0].started).getTime()).toBe(T0 + 1_500);
81
+ expect(result.lastTimestamp).toBe(T0 + 2_000);
82
+ });
83
+
84
+ test('drops segments that end before lastTimestamp', ({ expect }) => {
85
+ const segments: WhisperSegment[] = [
86
+ segment({
87
+ text: 'stale',
88
+ start: 0,
89
+ end: 0.5,
90
+ words: [{ word: 'stale', start: 0, end: 0.5 }],
91
+ }),
92
+ segment({
93
+ text: 'fresh',
94
+ start: 1,
95
+ end: 2,
96
+ words: [{ word: 'fresh', start: 1.5, end: 2 }],
97
+ }),
98
+ ];
99
+
100
+ const result = alignWhisperSegments(segments, [chunk(0)], T0 + 1_000);
101
+ expect(result.transcripts).toHaveLength(1);
102
+ expect(result.transcripts[0].text).toBe('fresh');
103
+ });
104
+ });
@@ -7,15 +7,18 @@ 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 DataType } from '@dxos/schema';
11
10
  import { trace } from '@dxos/tracing';
11
+ import { type ContentBlock } from '@dxos/types';
12
12
 
13
- import { TRANSCRIPTION_URL } from '../types';
14
13
  import { mergeFloat64Arrays } from '../util';
15
-
16
14
  import { type AudioChunk, type AudioRecorder } from './audio-recorder';
17
15
 
18
- type WhisperWord = {
16
+ /**
17
+ * Endpoint to the calls service.
18
+ */
19
+ const DEFAULT_TRANSCRIPTION_URL = 'https://calls-service.dxos.workers.dev';
20
+
21
+ export type WhisperWord = {
19
22
  word: string;
20
23
 
21
24
  /**
@@ -29,7 +32,7 @@ type WhisperWord = {
29
32
  end: number;
30
33
  };
31
34
 
32
- type WhisperSegment = {
35
+ export type WhisperSegment = {
33
36
  text: string;
34
37
 
35
38
  /**
@@ -61,16 +64,32 @@ export type TranscribeConfig = {
61
64
  * This is needed to catch the beginning of the user's speech.
62
65
  */
63
66
  prefixBufferChunksAmount: number;
67
+
68
+ /**
69
+ * Override the transcription endpoint base URL.
70
+ * Defaults to the DXOS calls service.
71
+ */
72
+ endpoint?: string;
64
73
  };
65
74
 
66
- export type TranscriberParams = {
75
+ /**
76
+ * Function that converts a base64-encoded WAV payload into Whisper segments.
77
+ * Allows callers to swap in alternative providers or mock the transport.
78
+ */
79
+ export type TranscribeFn = (audio: string) => Promise<WhisperSegment[]>;
80
+
81
+ export type TranscriberProps = {
67
82
  config: TranscribeConfig;
68
83
  recorder: AudioRecorder;
69
84
  /**
70
85
  * Callback to handle the transcribed segments, after all segment transformers are applied.
71
86
  * @param segments - The transcribed segments.
72
87
  */
73
- onSegments: (segments: DataType.MessageBlock.Transcript[]) => Promise<void>;
88
+ onSegments: (segments: ContentBlock.Transcript[]) => Promise<void>;
89
+ /**
90
+ * Optional override of the transcription transport. When provided, supersedes `config.endpoint`.
91
+ */
92
+ transcribe?: TranscribeFn;
74
93
  };
75
94
 
76
95
  /**
@@ -80,22 +99,24 @@ export type TranscriberParams = {
80
99
  */
81
100
  export class Transcriber extends Resource {
82
101
  private _audioChunks: AudioChunk[] = [];
83
- private _lastUsedTimestamp = 0;
102
+ private _lastTimestamp = 0;
84
103
 
85
104
  private readonly _openTrigger = new Trigger({ autoReset: true });
86
105
 
87
106
  private readonly _config: TranscribeConfig;
88
107
  private readonly _recorder: AudioRecorder;
89
- private readonly _onSegments: TranscriberParams['onSegments'];
108
+ private readonly _onSegments: TranscriberProps['onSegments'];
109
+ private readonly _transcribeFn?: TranscribeFn;
90
110
 
91
111
  private _recording = false;
92
112
  private _transcribeTask?: DeferredTask = undefined;
93
113
 
94
- constructor({ config, recorder, onSegments }: TranscriberParams) {
114
+ constructor({ config, recorder, onSegments, transcribe }: TranscriberProps) {
95
115
  super();
96
116
  this._config = config;
97
117
  this._recorder = recorder;
98
118
  this._onSegments = onSegments;
119
+ this._transcribeFn = transcribe;
99
120
  }
100
121
 
101
122
  protected override async _open(ctx: Context): Promise<void> {
@@ -192,67 +213,91 @@ export class Transcriber extends Resource {
192
213
  @trace.span({ showInBrowserTimeline: true })
193
214
  private async _fetchTranscription(audio: string): Promise<WhisperSegment[]> {
194
215
  if (audio.length === 0) {
195
- this._audioChunks = [];
196
216
  throw new Error('No audio to send for transcribing');
197
217
  }
198
218
 
199
- const response = await fetch(`${TRANSCRIPTION_URL}/transcribe`, {
200
- method: 'POST',
201
- body: JSON.stringify({ audio }),
202
- headers: {
203
- 'Content-Type': 'application/json',
204
- },
205
- });
206
-
207
- if (!response.ok) {
208
- this._audioChunks = [];
209
- throw new Error(`Transcription failed: ${response.statusText}`);
219
+ let segments: unknown;
220
+ if (this._transcribeFn) {
221
+ segments = await this._transcribeFn(audio);
222
+ } else {
223
+ // TODO(burdon): Create separate endpoint?
224
+ const endpoint = this._config.endpoint ?? DEFAULT_TRANSCRIPTION_URL;
225
+ const response = await fetch(`${endpoint}/transcribe`, {
226
+ method: 'POST',
227
+ body: JSON.stringify({ audio }),
228
+ headers: {
229
+ 'Content-Type': 'application/json',
230
+ },
231
+ });
232
+
233
+ if (!response.ok) {
234
+ throw new Error(`Transcription failed: ${response.statusText}`);
235
+ }
236
+
237
+ ({ segments } = (await response.json()) as { segments?: unknown });
210
238
  }
211
239
 
212
- const { segments } = (await response.json()) as {
213
- segments: WhisperSegment[];
214
- };
215
-
216
- log.info('transcription response', {
217
- segments: segments.length,
218
- string: segments.map((segments) => segments.text).join(' '),
219
- });
240
+ if (!Array.isArray(segments)) {
241
+ throw new Error('Transcription response payload is invalid');
242
+ }
220
243
 
221
- return segments;
244
+ log.info('transcription response', { segments: segments.length });
245
+ return segments as WhisperSegment[];
222
246
  }
223
247
 
224
- private _alignSegments(segments: WhisperSegment[], originalChunks: AudioChunk[]): DataType.MessageBlock.Transcript[] {
225
- // Absolute zero for all relative timestamps in the segments.
226
- const zeroTimestamp = originalChunks.at(0)!.timestamp;
227
-
228
- const filteredSegments = segments
229
- // Use segments that end after the last used timestamp.
230
- // Segments could overlap, so we need to filter words that starts after the last used timestamp.
231
- .filter((segment) => zeroTimestamp + segment.end * 1_000 >= this._lastUsedTimestamp)
232
- // Use words that starts after the last used timestamp.
233
- .map((segment) => {
234
- const words = segment.words.filter((word) => zeroTimestamp + word.start * 1_000 >= this._lastUsedTimestamp);
235
- return {
236
- ...segment,
237
- words,
238
- text: words.map((word) => word.word).join(''),
239
- start: words.at(0)?.start ?? segment.end,
240
- };
241
- })
242
- .filter((segment) => segment.words.length > 0);
243
-
244
- if (filteredSegments.length === 0) {
245
- return [];
248
+ private _alignSegments(segments: WhisperSegment[], originalChunks: AudioChunk[]): ContentBlock.Transcript[] {
249
+ const result = alignWhisperSegments(segments, originalChunks, this._lastTimestamp);
250
+ if (result.lastTimestamp !== undefined) {
251
+ this._lastTimestamp = result.lastTimestamp;
246
252
  }
247
253
 
248
- // Update last timestamp.
249
- this._lastUsedTimestamp = zeroTimestamp + filteredSegments.at(-1)!.end * 1_000;
254
+ return result.transcripts;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Pure helper that filters and absolute-timestamps Whisper segments against a chunk timeline.
260
+ * Exported for testing.
261
+ *
262
+ * @param segments - Raw segments returned by the Whisper service for `originalChunks`.
263
+ * @param originalChunks - Chunks fed into the transcription request (used for the zero timestamp).
264
+ * @param lastTimestamp - Most recent absolute timestamp already emitted; segments whose end
265
+ * falls strictly before this point are deduped out, as are individual words whose start does.
266
+ */
267
+ export const alignWhisperSegments = (
268
+ segments: WhisperSegment[],
269
+ originalChunks: AudioChunk[],
270
+ lastTimestamp: number,
271
+ ): { transcripts: ContentBlock.Transcript[]; lastTimestamp?: number } => {
272
+ if (originalChunks.length === 0) {
273
+ return { transcripts: [] };
274
+ }
275
+
276
+ const zeroTimestamp = originalChunks[0].timestamp;
277
+
278
+ const filteredSegments = segments
279
+ .filter((segment) => zeroTimestamp + segment.end * 1_000 >= lastTimestamp)
280
+ .map((segment) => {
281
+ const words = segment.words.filter((word) => zeroTimestamp + word.start * 1_000 >= lastTimestamp);
282
+ return {
283
+ ...segment,
284
+ words,
285
+ text: words.map((word) => word.word).join(''),
286
+ start: words.at(0)?.start ?? segment.end,
287
+ };
288
+ })
289
+ .filter((segment) => segment.words.length > 0);
290
+
291
+ if (filteredSegments.length === 0) {
292
+ return { transcripts: [] };
293
+ }
250
294
 
251
- // Add absolute timestamp to each segment.
252
- return filteredSegments.map((segment) => ({
295
+ return {
296
+ lastTimestamp: zeroTimestamp + filteredSegments.at(-1)!.end * 1_000,
297
+ transcripts: filteredSegments.map((segment) => ({
253
298
  _tag: 'transcript',
254
299
  started: new Date(zeroTimestamp + segment.start * 1_000).toISOString(),
255
300
  text: segment.text.trim(),
256
- }));
257
- }
258
- }
301
+ })),
302
+ };
303
+ };
@@ -2,14 +2,17 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { signal } from '@preact/signals-core';
5
+ import { Atom, type Registry } from '@effect-atom/atom-react';
6
+ import * as Effect from 'effect/Effect';
7
+ import * as Layer from 'effect/Layer';
6
8
 
7
9
  import { synchronized } from '@dxos/async';
10
+ import { createFeedServiceLayer, type Space } from '@dxos/client/echo';
8
11
  import { Resource } from '@dxos/context';
9
- import { Obj } from '@dxos/echo';
10
- import { type Queue } from '@dxos/echo-db';
12
+ import { Feed, Obj } from '@dxos/echo';
13
+ import { EffectEx } from '@dxos/effect';
11
14
  import { type EdgeHttpClient } from '@dxos/react-edge-client';
12
- import { DataType } from '@dxos/schema';
15
+ import { type ContentBlock, Message } from '@dxos/types';
13
16
 
14
17
  import { MediaStreamRecorder } from './media-stream-recorder';
15
18
  import { Transcriber } from './transcriber';
@@ -30,13 +33,14 @@ const PREFIXED_CHUNKS_AMOUNT = 10;
30
33
  */
31
34
  const TRANSCRIBE_AFTER_CHUNKS_AMOUNT = 50;
32
35
 
33
- export type TranscriptMessageEnricher = (message: DataType.Message) => Promise<DataType.Message>;
36
+ export type TranscriptMessageEnricher = (message: Message.Message) => Promise<Message.Message>;
34
37
 
35
38
  export type TranscriptionManagerOptions = {
36
39
  edgeClient: EdgeHttpClient;
40
+ registry: Registry.Registry;
37
41
 
38
42
  /**
39
- * Enrich the message before it is written to the transcription queue.
43
+ * Enrich the message before it is written to the transcription feed.
40
44
  */
41
45
  messageEnricher?: TranscriptMessageEnricher;
42
46
  };
@@ -47,26 +51,33 @@ export type TranscriptionManagerOptions = {
47
51
  export class TranscriptionManager extends Resource {
48
52
  private readonly _edgeClient: EdgeHttpClient;
49
53
  private readonly _messageEnricher?: TranscriptMessageEnricher;
54
+ private readonly _registry: Registry.Registry;
50
55
  private _audioStreamTrack?: MediaStreamTrack = undefined;
51
56
  private _identityDid?: string = undefined;
52
57
  private _mediaRecorder?: MediaStreamRecorder = undefined;
53
58
  private _transcriber?: Transcriber = undefined;
54
- private _queue?: Queue<DataType.Message> = undefined;
55
- private _enabled = signal(false);
59
+ private _feed?: Feed.Feed = undefined;
60
+ private _feedServiceLayer?: Layer.Layer<Feed.FeedService> = undefined;
61
+ private _enabledAtom = Atom.make(false);
56
62
 
57
63
  constructor(options: TranscriptionManagerOptions) {
58
64
  super();
59
65
  this._edgeClient = options.edgeClient;
60
66
  this._messageEnricher = options.messageEnricher;
67
+ this._registry = options.registry;
61
68
  }
62
69
 
63
- /** @reactive */
64
- get enabled() {
65
- return this._enabled.value;
70
+ get enabled(): Atom.Atom<boolean> {
71
+ return this._enabledAtom;
66
72
  }
67
73
 
68
- setQueue(queue: Queue<DataType.Message>): this {
69
- this._queue = queue;
74
+ getEnabled(): boolean {
75
+ return this._registry.get(this._enabledAtom);
76
+ }
77
+
78
+ setFeed(space: Space, feed: Feed.Feed): this {
79
+ this._feed = feed;
80
+ this._feedServiceLayer = createFeedServiceLayer(space.queues);
70
81
  return this;
71
82
  }
72
83
 
@@ -78,7 +89,7 @@ export class TranscriptionManager extends Resource {
78
89
  }
79
90
 
80
91
  setRecording(recording?: boolean): this {
81
- if (!this.isOpen || !this._enabled.value) {
92
+ if (!this.isOpen || !this.getEnabled()) {
82
93
  return this;
83
94
  }
84
95
 
@@ -90,19 +101,17 @@ export class TranscriptionManager extends Resource {
90
101
  return this;
91
102
  }
92
103
 
93
- /**
94
- * Enable or disable transcription.
95
- * @param enabled - Whether to enable transcription.
96
- */
97
- @synchronized
98
- async setEnabled(enabled?: boolean): Promise<void> {
99
- if (this._enabled.value === enabled) {
104
+ async setEnabled(enabled: boolean): Promise<void> {
105
+ if (this.getEnabled() === enabled) {
100
106
  return;
101
107
  }
102
108
 
103
- this._enabled.value = enabled ?? false;
104
- // TODO(burdon): Why is toggle called here?
105
- this.isOpen && (await this._toggleTranscriber());
109
+ this._registry.set(this._enabledAtom, enabled ?? false);
110
+ if (enabled) {
111
+ await this._maybeRestartTranscriber();
112
+ } else {
113
+ await this._stopTranscriber();
114
+ }
106
115
  }
107
116
 
108
117
  @synchronized
@@ -112,48 +121,23 @@ export class TranscriptionManager extends Resource {
112
121
  }
113
122
 
114
123
  this._audioStreamTrack = track;
115
- this.isOpen && (await this._toggleTranscriber());
124
+ await this._maybeRestartTranscriber();
116
125
  }
117
126
 
118
127
  protected override async _open(): Promise<void> {
119
- await this._toggleTranscriber();
128
+ await this._maybeRestartTranscriber();
120
129
  }
121
130
 
122
131
  protected override async _close(): Promise<void> {
123
- void this._transcriber?.close();
124
- }
125
-
126
- // TODO(burdon): Change this to setEnables (explicit), not toggle.
127
- private async _toggleTranscriber(): Promise<void> {
128
- await this._maybeReinitTranscriber();
129
-
130
- // Open or close transcriber if transcription is enabled or disabled.
131
- if (this._enabled.value) {
132
- await this._transcriber?.open();
133
- // TODO(burdon): Started and stopped blocks appear twice.
134
- const block = Obj.make(DataType.Message, {
135
- created: new Date().toISOString(),
136
- blocks: [{ _tag: 'transcript', text: 'Started', started: new Date().toISOString() }],
137
- sender: { role: 'assistant' },
138
- });
139
- await this._queue?.append([block]);
140
- } else {
141
- await this._transcriber?.close();
142
- const block = Obj.make(DataType.Message, {
143
- created: new Date().toISOString(),
144
- blocks: [{ _tag: 'transcript', text: 'Stopped', started: new Date().toISOString() }],
145
- sender: { role: 'assistant' },
146
- });
147
- await this._queue?.append([block]);
148
- }
132
+ await this._stopTranscriber();
149
133
  }
150
134
 
151
- private async _maybeReinitTranscriber(): Promise<void> {
152
- if (!this._audioStreamTrack || !this._enabled.value) {
135
+ private async _maybeRestartTranscriber(): Promise<void> {
136
+ if (!this._audioStreamTrack || !this.getEnabled() || !this.isOpen) {
153
137
  return;
154
138
  }
155
139
 
156
- // Reinitialize transcriber if queue or media stream track has changed.
140
+ // Reinitialize transcriber if feed or media stream track has changed.
157
141
  let needReinit = false;
158
142
  if (this._audioStreamTrack !== this._mediaRecorder?.mediaStreamTrack) {
159
143
  this._mediaRecorder = new MediaStreamRecorder({
@@ -172,15 +156,21 @@ export class TranscriptionManager extends Resource {
172
156
  recorder: this._mediaRecorder,
173
157
  onSegments: (segments) => this._onSegments(segments),
174
158
  });
159
+
160
+ await this._transcriber?.open();
175
161
  }
176
162
  }
177
163
 
178
- private async _onSegments(segments: DataType.MessageBlock.Transcript[]): Promise<void> {
179
- if (!this.isOpen || !this._queue) {
164
+ private async _stopTranscriber(): Promise<void> {
165
+ await this._transcriber?.close();
166
+ }
167
+
168
+ private async _onSegments(segments: ContentBlock.Transcript[]): Promise<void> {
169
+ if (!this.isOpen || !this._feed || !this._feedServiceLayer) {
180
170
  return;
181
171
  }
182
172
 
183
- let block = Obj.make(DataType.Message, {
173
+ let block = Obj.make(Message.Message, {
184
174
  created: new Date().toISOString(),
185
175
  blocks: segments,
186
176
  sender: { identityDid: this._identityDid },
@@ -190,6 +180,6 @@ export class TranscriptionManager extends Resource {
190
180
  block = await this._messageEnricher(block);
191
181
  }
192
182
 
193
- await this._queue.append([block]);
183
+ await Feed.append(this._feed, [block]).pipe(Effect.provide(this._feedServiceLayer), EffectEx.runAndForwardErrors);
194
184
  }
195
185
  }
@@ -4,20 +4,23 @@
4
4
 
5
5
  import { type Resource } from '@dxos/react-ui';
6
6
 
7
- import { meta } from './meta';
7
+ import { meta } from '#meta';
8
8
 
9
9
  export const translations = [
10
10
  {
11
11
  'en-US': {
12
12
  [meta.id]: {
13
- 'plugin name': 'Transcription',
14
- 'transcript companion label': 'Transcript',
13
+ 'plugin.name': 'Transcription',
14
+ 'transcript-companion.label': 'Transcript',
15
15
 
16
- 'delete button': 'Delete',
17
- 'bookmark button': 'Bookmark',
18
- 'scroll to end label': 'Scroll to latest',
16
+ 'delete.button': 'Delete',
17
+ 'bookmark.button': 'Bookmark',
18
+ 'scroll-to-end.label': 'Scroll to latest',
19
19
 
20
- 'settings entity extraction label': 'Entity extraction',
20
+ 'start-recording.label': 'Start recording',
21
+ 'stop-recording.label': 'Stop recording',
22
+
23
+ 'settings.entity-extraction.label': 'Entity extraction',
21
24
  },
22
25
  },
23
26
  },
@@ -0,0 +1,106 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ // @import-as-namespace
6
+
7
+ import * as Schema from 'effect/Schema';
8
+
9
+ import { AiService } from '@dxos/ai';
10
+ import { SpaceSchema } from '@dxos/client/echo';
11
+ import { Operation } from '@dxos/compute';
12
+ import { Database, Feed, Ref, Type, DXN } from '@dxos/echo';
13
+ import { Message, Transcript } from '@dxos/types';
14
+
15
+ import { meta } from '#meta';
16
+
17
+ const makeKey = (name: string) => DXN.make(`${meta.id}.operation.${name}`);
18
+
19
+ export const Create = Operation.make({
20
+ meta: { key: makeKey('create'), name: 'Create Transcript', icon: 'ph--microphone--regular' },
21
+ input: Schema.Struct({
22
+ name: Schema.optional(Schema.String),
23
+ space: SpaceSchema,
24
+ }),
25
+ output: Schema.Struct({
26
+ object: Type.getSchema(Transcript.Transcript),
27
+ }),
28
+ });
29
+
30
+ export const MessageWithRangeId = Schema.extend(
31
+ Type.getSchema(Message.Message),
32
+ Schema.Struct({
33
+ rangeId: Schema.optional(Schema.Array(Schema.String)).annotations({
34
+ description: 'The IDs of the messages that contain the sentences.',
35
+ }),
36
+ }),
37
+ );
38
+
39
+ export type MessageWithRangeIdType = Schema.Schema.Type<typeof MessageWithRangeId>;
40
+
41
+ export const Open = Operation.make({
42
+ meta: {
43
+ key: DXN.make('org.dxos.function.transcription.open'),
44
+ name: 'Open',
45
+ description: 'Opens and reads the contents of a transcription object.',
46
+ icon: 'ph--folder-open--regular',
47
+ },
48
+ input: Schema.Struct({
49
+ transcript: Ref.Ref(Transcript.Transcript).annotations({
50
+ description: 'The ID of the transcription object.',
51
+ }),
52
+ }),
53
+ output: Schema.Struct({
54
+ content: Schema.String,
55
+ }),
56
+ services: [Database.Service, Feed.FeedService],
57
+ });
58
+
59
+ export const Summarize = Operation.make({
60
+ meta: {
61
+ key: DXN.make('org.dxos.function.transcription.summarize'),
62
+ name: 'Summarize',
63
+ description: 'Summarize a transcript of a meeting.',
64
+ icon: 'ph--text-align-left--regular',
65
+ },
66
+ input: Schema.Struct({
67
+ transcript: Schema.String.annotations({
68
+ description: 'The transcript of the meeting.',
69
+ }),
70
+ notes: Schema.optional(Schema.String).annotations({
71
+ description: 'Additional notes from the participants.',
72
+ }),
73
+ }),
74
+ output: Schema.Struct({
75
+ summary: Schema.String.annotations({
76
+ description: 'The summary of the transcript.',
77
+ }),
78
+ }),
79
+ services: [AiService.AiService],
80
+ });
81
+
82
+ export const SentenceNormalizationInput = Schema.Struct({
83
+ messages: Schema.Array(MessageWithRangeId).annotations({
84
+ description: 'Messages to normalize into sentences.',
85
+ }),
86
+ });
87
+
88
+ export type SentenceNormalizationInputType = Schema.Schema.Type<typeof SentenceNormalizationInput>;
89
+
90
+ export const SentenceNormalizationOutput = Schema.Struct({
91
+ sentences: Schema.Array(MessageWithRangeId.pipe(Schema.mutable)).pipe(Schema.mutable).annotations({
92
+ description: 'The sentences of the transcript.',
93
+ }),
94
+ });
95
+
96
+ export const SentenceNormalization = Operation.make({
97
+ meta: {
98
+ key: DXN.make('org.dxos.function.transcription.sentenceNormalization'),
99
+ name: 'Sentence Normalization',
100
+ description: 'Post process of transcription for sentence normalization',
101
+ icon: 'ph--text-t--regular',
102
+ },
103
+ input: SentenceNormalizationInput,
104
+ output: SentenceNormalizationOutput,
105
+ services: [],
106
+ });