@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
@@ -4,9 +4,10 @@
4
4
 
5
5
  import { useEffect, useMemo } from 'react';
6
6
 
7
- import { useCapabilities } from '@dxos/app-framework';
7
+ import { useCapabilities } from '@dxos/app-framework/ui';
8
+
9
+ import { TranscriptionCapabilities } from '#types';
8
10
 
9
- import { TranscriptionCapabilities } from '../capabilities';
10
11
  import { type Transcriber } from '../transcriber';
11
12
 
12
13
  /**
@@ -17,17 +18,24 @@ export const useTranscriber = ({
17
18
  recorderConfig,
18
19
  transcriberConfig,
19
20
  onSegments,
20
- }: Partial<TranscriptionCapabilities.GetTranscriberProps>) => {
21
- const [getTranscriber] = useCapabilities(TranscriptionCapabilities.Transcriber);
21
+ transcribe,
22
+ }: Partial<TranscriptionCapabilities.TranscriberProviderProps>) => {
23
+ const [transcriberProvider] = useCapabilities(TranscriptionCapabilities.TranscriberProvider);
22
24
 
23
25
  // Initialize audio transcription.
24
26
  const transcriber = useMemo<Transcriber | undefined>(() => {
25
- if (!getTranscriber || !audioStreamTrack || !onSegments) {
27
+ if (!transcriberProvider || !audioStreamTrack || !onSegments) {
26
28
  return undefined;
27
29
  }
28
30
 
29
- return getTranscriber({ audioStreamTrack, recorderConfig, transcriberConfig, onSegments });
30
- }, [getTranscriber, audioStreamTrack, recorderConfig, transcriberConfig, onSegments]);
31
+ return transcriberProvider({
32
+ audioStreamTrack,
33
+ recorderConfig,
34
+ transcriberConfig,
35
+ onSegments,
36
+ transcribe,
37
+ });
38
+ }, [transcriberProvider, audioStreamTrack, recorderConfig, transcriberConfig, onSegments, transcribe]);
31
39
 
32
40
  useEffect(() => {
33
41
  return () => {
@@ -0,0 +1,87 @@
1
+ //
2
+ // Copyright 2024 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import { useCallback, useEffect, useState } from 'react';
7
+
8
+ import { createFeedServiceLayer } from '@dxos/client/echo';
9
+ import { Feed, Obj } from '@dxos/echo';
10
+ import { EffectEx } from '@dxos/effect';
11
+ import { log } from '@dxos/log';
12
+ import { getSpace } from '@dxos/react-client/echo';
13
+ import { useIdentity } from '@dxos/react-client/halo';
14
+ import { Message, type Transcript } from '@dxos/types';
15
+
16
+ import { useAudioTrack } from './useAudioTrack';
17
+ import { useTranscriber } from './useTranscriber';
18
+
19
+ export type TranscriptionRecording = {
20
+ recording: boolean;
21
+ toggleRecording: () => void;
22
+ };
23
+
24
+ /**
25
+ * Drives the recording lifecycle for a transcript: opens an audio track, feeds it through the
26
+ * transcriber, and appends transcribed message batches to the transcript's feed. Returns the
27
+ * recording flag and a toggle callback for the caller to wire to UI.
28
+ */
29
+ export const useTranscriptionRecording = (transcript: Transcript.Transcript): TranscriptionRecording => {
30
+ const space = getSpace(transcript);
31
+ const identity = useIdentity();
32
+ const feed = transcript.feed.target;
33
+
34
+ const [recording, setRecording] = useState(false);
35
+ const track = useAudioTrack(recording);
36
+
37
+ // Append a transcribed message batch to the transcript's feed.
38
+ const handleSegments = useCallback(
39
+ async (blocks: Message.Message['blocks']) => {
40
+ if (!space || !feed || blocks.length === 0) {
41
+ return;
42
+ }
43
+ const sender = identity ? { identityDid: identity.did, name: identity.profile?.displayName } : {};
44
+ const message = Obj.make(Message.Message, {
45
+ sender,
46
+ created: new Date().toISOString(),
47
+ blocks,
48
+ });
49
+ const feedServiceLayer = createFeedServiceLayer(space.queues);
50
+ await Feed.append(feed, [message]).pipe(Effect.provide(feedServiceLayer), EffectEx.runAndForwardErrors);
51
+ },
52
+ [space, feed, identity],
53
+ );
54
+
55
+ // Drive the transcriber lifecycle off the recording flag + audio track.
56
+ const transcriber = useTranscriber({ audioStreamTrack: track, onSegments: handleSegments });
57
+ useEffect(() => {
58
+ if (!transcriber) {
59
+ return;
60
+ }
61
+ let cancelled = false;
62
+ // If `open()` rejects (e.g. mic permission denied, device init failure) we must
63
+ // clear `recording` — otherwise the toolbar button reports "stop" forever while
64
+ // nothing is actually being captured.
65
+ void transcriber.open().then(
66
+ () => {
67
+ if (!cancelled && recording) {
68
+ transcriber.startChunksRecording();
69
+ }
70
+ },
71
+ (err) => {
72
+ if (!cancelled) {
73
+ log.catch(err);
74
+ setRecording(false);
75
+ }
76
+ },
77
+ );
78
+ return () => {
79
+ cancelled = true;
80
+ transcriber.stopChunksRecording();
81
+ };
82
+ }, [transcriber, recording]);
83
+
84
+ const toggleRecording = useCallback(() => setRecording((value) => !value), []);
85
+
86
+ return { recording, toggleRecording };
87
+ };
@@ -7,10 +7,9 @@ import { useCallback, useEffect, useState } from 'react';
7
7
  import { scheduleMicroTask } from '@dxos/async';
8
8
  import { Context } from '@dxos/context';
9
9
  import { log } from '@dxos/log';
10
- import { useSoundEffect } from '@dxos/react-ui-sfx';
11
-
12
- import { type TranscriberParams } from '../transcriber';
10
+ import { useSoundEffect } from '@dxos/react-ui-audio';
13
11
 
12
+ import { type TranscriberProps } from '../transcriber';
14
13
  import { useAudioTrack } from './useAudioTrack';
15
14
  import { useTranscriber } from './useTranscriber';
16
15
 
@@ -26,7 +25,7 @@ export const useVoiceInput = ({ active, onUpdate }: UseVoiceInputProps) => {
26
25
  const soundStart = useSoundEffect('StartRecording');
27
26
  const soundStop = useSoundEffect('StopRecording');
28
27
 
29
- const handleSegments = useCallback<TranscriberParams['onSegments']>(async (segments) => {
28
+ const handleSegments = useCallback<TranscriberProps['onSegments']>(async (segments) => {
30
29
  const text = segments.map((str) => str.text.trim().replace(/[^\w\s]/g, '')).join(' ');
31
30
  onUpdate(text);
32
31
  }, []);
package/src/index.ts CHANGED
@@ -2,11 +2,10 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- export { TranscriptionCapabilities } from './capabilities';
6
-
7
- export * from './components';
5
+ // TODO(wittjosiah): Hooks should not be exported from the plugin package at all.
6
+ // Either refactor callers to not need them or factor them out to a shared package.
7
+ export * from './blueprints';
8
8
  export * from './hooks';
9
9
  export * from './meta';
10
10
  export * from './transcriber';
11
-
12
- export * from './TranscriptionPlugin';
11
+ export * from './types';
package/src/meta.ts CHANGED
@@ -2,16 +2,41 @@
2
2
  // Copyright 2023 DXOS.org
3
3
  //
4
4
 
5
- import { type PluginMeta } from '@dxos/app-framework';
5
+ import { Plugin } from '@dxos/app-framework';
6
+ import { DXN } from '@dxos/keys';
7
+ import { trim } from '@dxos/util';
6
8
 
7
- export const TRANSCRIPTION_PLUGIN = 'dxos.org/plugin/transcription';
8
-
9
- export const meta: PluginMeta = {
10
- id: TRANSCRIPTION_PLUGIN,
9
+ export const meta = Plugin.makeMeta({
10
+ key: DXN.make('org.dxos.plugin.transcription'),
11
11
  name: 'Transcription',
12
- description: 'Voice transcription.',
12
+ author: 'DXOS',
13
+ description: trim`
14
+ Real-time voice-to-text transcription for DXOS Composer.
15
+ Captures microphone audio in short PCM chunks, batches them into WAV payloads, and streams
16
+ the results to a Whisper-compatible speech-recognition endpoint.
17
+ Transcribed segments are timestamped, deduplicated across chunk boundaries, and persisted
18
+ as Message objects in an ECHO Feed so that every participant in a shared space sees the
19
+ live transcript without any manual sync step.
20
+
21
+ Each recording session is represented as a Transcript object linked to its Feed.
22
+ The read-only editor renders messages with speaker bylines and wall-clock timestamps,
23
+ supporting markdown decoration and document preview.
24
+ An optional message enricher pipeline lets plugins annotate messages before they are
25
+ committed — for example, to attach speaker identity from a calls service.
26
+
27
+ The plugin ships two blueprint-compatible operations: Open (loads and formats a transcript
28
+ for reading by an AI assistant) and Summarize (sends the transcript text to an LLM and
29
+ returns a structured Markdown summary with key points, verbatim quotes, and actionable
30
+ tasks extracted from the conversation).
31
+
32
+ A sentence-normalization pass merges raw word-level tokens from the recognizer into
33
+ grammatically complete sentences, improving readability of the stored transcript without
34
+ altering the underlying audio timeline.
35
+ `,
13
36
  icon: 'ph--microphone--regular',
37
+ iconHue: 'sky',
14
38
  source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-transcription',
39
+ spec: 'PLUGIN.mdl',
15
40
  tags: ['labs'],
16
41
  screenshots: [],
17
- };
42
+ });
@@ -6,13 +6,13 @@ import { EditorView } from '@codemirror/view';
6
6
  import { describe, test } from 'vitest';
7
7
 
8
8
  import { Obj } from '@dxos/echo';
9
- import type { ObjectId } from '@dxos/keys';
10
- import { DataType } from '@dxos/schema';
9
+ import type { EntityId } from '@dxos/keys';
10
+ import { Message } from '@dxos/types';
11
11
 
12
12
  import { type ChunkRenderer, DocumentAdapter, SerializationModel } from './model';
13
13
 
14
- const blockToMarkdown: ChunkRenderer<DataType.Message> = (
15
- message: DataType.Message,
14
+ const blockToMarkdown: ChunkRenderer<Message.Message> = (
15
+ message: Message.Message,
16
16
  index: number,
17
17
  debug = true,
18
18
  ): string[] => {
@@ -27,12 +27,12 @@ const createDate = () => new Date().toISOString();
27
27
 
28
28
  describe('SerializationModel', () => {
29
29
  test('basic', ({ expect }) => {
30
- const model = new SerializationModel<DataType.Message>(blockToMarkdown);
30
+ const model = new SerializationModel<Message.Message>(blockToMarkdown);
31
31
  expect(model.chunks.length).to.eq(0);
32
32
  expect(model.doc.toString()).to.eq('');
33
33
 
34
34
  // Create message.
35
- const message = Obj.make(DataType.Message, {
35
+ const message = Obj.make(Message.Message, {
36
36
  created: createDate(),
37
37
  sender: { name: 'Alice' },
38
38
  blocks: [
@@ -51,7 +51,9 @@ describe('SerializationModel', () => {
51
51
  }
52
52
 
53
53
  // Update message.
54
- message.blocks.push({ _tag: 'transcript', started: createDate(), text: 'Hello again!' });
54
+ Obj.update(message, (message) => {
55
+ message.blocks.push({ _tag: 'transcript', started: createDate(), text: 'Hello again!' });
56
+ });
55
57
  model.updateChunk(message);
56
58
  {
57
59
  const text = model.doc.toString();
@@ -62,14 +64,14 @@ describe('SerializationModel', () => {
62
64
 
63
65
  test('sync - append', ({ expect }) => {
64
66
  const view = new EditorView({ extensions: [], doc: '' });
65
- const model = new SerializationModel<DataType.Message>(blockToMarkdown);
67
+ const model = new SerializationModel<Message.Message>(blockToMarkdown);
66
68
  const adapter = new DocumentAdapter(view);
67
69
  expect(adapter.lineCount()).to.eq(0);
68
70
  expect(view.state.doc.toString()).to.eq('');
69
71
 
70
72
  // Append message.
71
73
  {
72
- const message = Obj.make(DataType.Message, {
74
+ const message = Obj.make(Message.Message, {
73
75
  created: createDate(),
74
76
  sender: { name: 'Alice' },
75
77
  blocks: [
@@ -87,7 +89,7 @@ describe('SerializationModel', () => {
87
89
 
88
90
  // Append message.
89
91
  {
90
- const message = Obj.make(DataType.Message, {
92
+ const message = Obj.make(Message.Message, {
91
93
  created: createDate(),
92
94
  sender: { name: 'Bob' },
93
95
  blocks: [
@@ -106,15 +108,15 @@ describe('SerializationModel', () => {
106
108
 
107
109
  test('sync - append, update, delete', ({ expect }) => {
108
110
  const view = new EditorView({ extensions: [], doc: '' });
109
- const model = new SerializationModel<DataType.Message>(blockToMarkdown);
111
+ const model = new SerializationModel<Message.Message>(blockToMarkdown);
110
112
  const adapter = new DocumentAdapter(view);
111
113
  expect(adapter.lineCount()).to.eq(0);
112
114
 
113
- let msgId: ObjectId;
115
+ let msgId: EntityId;
114
116
 
115
117
  // Append message.
116
118
  {
117
- const message = Obj.make(DataType.Message, {
119
+ const message = Obj.make(Message.Message, {
118
120
  created: createDate(),
119
121
  sender: { name: 'Alice' },
120
122
  blocks: [
@@ -131,13 +133,17 @@ describe('SerializationModel', () => {
131
133
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello world!\n\n');
132
134
 
133
135
  // Update message (add block).
134
- message.blocks.push({ _tag: 'transcript', started: createDate(), text: 'Hello again!' });
136
+ Obj.update(message, (message) => {
137
+ message.blocks.push({ _tag: 'transcript', started: createDate(), text: 'Hello again!' });
138
+ });
135
139
  model.updateChunk(message);
136
140
  model.sync(adapter);
137
141
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello world!\nHello again!\n\n');
138
142
 
139
143
  // Update message (remove block).
140
- message.blocks.splice(0, 1);
144
+ Obj.update(message, (message) => {
145
+ message.blocks.splice(0, 1);
146
+ });
141
147
  model.updateChunk(message);
142
148
  model.sync(adapter);
143
149
  expect(view.state.doc.toString()).to.eq('###### Alice\nHello again!\n\n');
@@ -147,7 +153,7 @@ describe('SerializationModel', () => {
147
153
 
148
154
  // Append message.
149
155
  {
150
- const message = Obj.make(DataType.Message, {
156
+ const message = Obj.make(Message.Message, {
151
157
  created: createDate(),
152
158
  sender: { name: 'Bob' },
153
159
  blocks: [{ _tag: 'transcript', started: createDate(), text: 'Hello again!' }],
@@ -80,6 +80,9 @@ type ChunkChange<T extends Chunk> =
80
80
  * Instead this model tracks changes and syncs them with the ChunkDocument.
81
81
  */
82
82
  export class SerializationModel<T extends Chunk> {
83
+ /** Emits when the document is updated. */
84
+ public readonly update = new Event<void>();
85
+
83
86
  /** Ordered set of chunks. */
84
87
  private readonly _chunks: T[] = [];
85
88
 
@@ -92,9 +95,6 @@ export class SerializationModel<T extends Chunk> {
92
95
  /** Track chunk changes since last sync. */
93
96
  private readonly _changes: Array<ChunkChange<T>> = [];
94
97
 
95
- /** Emits when the document is updated. */
96
- public readonly update = new Event<void>();
97
-
98
98
  constructor(
99
99
  private readonly _renderer: ChunkRenderer<T>,
100
100
  initialChunks: T[] = [],
@@ -2,28 +2,27 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- //
6
- // Copyright 2025 DXOS.org
7
- //
8
-
9
- import { effect } from '@preact/signals-core';
5
+ import * as Effect from 'effect/Effect';
6
+ import type * as Runtime from 'effect/Runtime';
10
7
 
11
8
  import { DeferredTask, asyncTimeout } from '@dxos/async';
12
9
  import { LifecycleState, Resource } from '@dxos/context';
13
- import { type Queue } from '@dxos/echo-db';
14
- import { type FunctionExecutor } from '@dxos/functions';
10
+ import { Feed, Filter } from '@dxos/echo';
11
+ import { EffectEx } from '@dxos/effect';
12
+ import { type FunctionExecutor } from '@dxos/functions-runtime';
15
13
  import { log } from '@dxos/log';
16
- import { type DataType } from '@dxos/schema';
14
+ import { Message } from '@dxos/types';
17
15
 
18
- import { type MessageWithRangeId, sentenceNormalization } from './normalization';
16
+ import { type MessageWithRangeId, type NormalizationOutput, sentenceNormalization } from './normalization';
19
17
  import { getActorId } from './utils';
20
18
 
21
19
  const PROCESSING_TIMEOUT = 20_000; // ms
22
20
  const MAX_RANGE_ID_COUNT = 10;
23
21
 
24
- export type SegmentsNormalizerParams = {
22
+ export type SegmentsNormalizerProps = {
25
23
  functionExecutor: FunctionExecutor;
26
- queue: Queue<DataType.Message>;
24
+ feed: Feed.Feed;
25
+ feedRuntime: Runtime.Runtime<Feed.FeedService>;
27
26
  startingCursor: QueueCursor;
28
27
  };
29
28
 
@@ -33,37 +32,51 @@ export type QueueCursor = {
33
32
  timestamp: string;
34
33
  };
35
34
 
36
- // TODO(mykola): .
37
35
  export class MessageNormalizer extends Resource {
38
36
  private readonly _functionExecutor: FunctionExecutor;
39
- private _queue: Queue<DataType.Message>;
37
+
38
+ private _feed: Feed.Feed;
39
+ private _feedRuntime: Runtime.Runtime<Feed.FeedService>;
40
40
  private _cursor: QueueCursor;
41
41
  private _messagesToProcess: MessageWithRangeId[] = [];
42
42
  private _normalizationTask?: DeferredTask;
43
43
  private _lastProcessedMessageIds?: string[];
44
44
 
45
- constructor({ functionExecutor, queue, startingCursor }: SegmentsNormalizerParams) {
45
+ constructor({ functionExecutor, feed, feedRuntime, startingCursor }: SegmentsNormalizerProps) {
46
46
  super();
47
47
  this._functionExecutor = functionExecutor;
48
- this._queue = queue;
48
+ this._feed = feed;
49
+ this._feedRuntime = feedRuntime;
49
50
  this._cursor = startingCursor;
50
51
  }
51
52
 
52
53
  protected override async _open(): Promise<void> {
53
54
  this._normalizationTask = new DeferredTask(this._ctx, () => this._processMessages());
54
- const unsubscribe = effect(() => {
55
+
56
+ const queryResult = await Feed.query(this._feed, Filter.type(Message.Message)).pipe(
57
+ Effect.provide(this._feedRuntime),
58
+ EffectEx.runAndForwardErrors,
59
+ );
60
+
61
+ const updateMessages = () => {
55
62
  if (this._lifecycleState !== LifecycleState.OPEN) {
56
63
  return;
57
64
  }
58
65
 
59
- this._messagesToProcess = this._queue.objects.filter((message) => {
66
+ this._messagesToProcess = (queryResult.results as Message.Message[]).filter((message) => {
60
67
  const actorId = getActorId(message.sender);
61
68
  return actorId === this._cursor.actorId && message.created >= this._cursor.timestamp;
62
69
  });
63
70
 
64
71
  this._normalizationTask!.schedule();
65
- });
66
- this._ctx.onDispose(() => unsubscribe());
72
+ };
73
+
74
+ // Initial update.
75
+ updateMessages();
76
+
77
+ // Subscribe to feed changes.
78
+ const unsubscribe = queryResult.subscribe(updateMessages);
79
+ this._ctx.onDispose(unsubscribe);
67
80
  }
68
81
 
69
82
  // Need to unpack strings from blocks from messages run them through the function and then pack them back into blocks into messages.
@@ -81,12 +94,12 @@ export class MessageNormalizer extends Resource {
81
94
 
82
95
  try {
83
96
  // TODO(mykola): Executor should support timeout.
84
- const response = await asyncTimeout(
97
+ const response: NormalizationOutput = await asyncTimeout(
85
98
  this._functionExecutor.invoke(sentenceNormalization, { messages }),
86
99
  PROCESSING_TIMEOUT,
87
100
  );
88
101
 
89
- this._writeMessages(response.sentences);
102
+ await this._writeMessages(response.sentences);
90
103
  this._lastProcessedMessageIds.push(...response.sentences.map((sentence) => sentence.id));
91
104
  if (response.sentences.length === 1 && response.sentences.at(-1)!.rangeId!.length > MAX_RANGE_ID_COUNT) {
92
105
  log.warn('Sentence is too long', { messages });
@@ -95,14 +108,14 @@ export class MessageNormalizer extends Resource {
95
108
  } catch {
96
109
  log.error('Failed to normalize segments', { messages });
97
110
  // If processing failed, emit the segments as is.
98
- this._writeMessages(messages);
111
+ await this._writeMessages(messages);
99
112
  }
100
113
  }
101
114
 
102
- private _writeMessages(messages: MessageWithRangeId[]): void {
115
+ private async _writeMessages(messages: MessageWithRangeId[]): Promise<void> {
103
116
  log.info('writing messages', { messages });
104
117
  const lastMessage = messages[messages.length - 1];
105
118
  this._cursor.timestamp = lastMessage.created;
106
- void this._queue.append(messages);
119
+ await Feed.append(this._feed, messages).pipe(Effect.provide(this._feedRuntime), EffectEx.runAndForwardErrors);
107
120
  }
108
121
  }
@@ -2,23 +2,16 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { effect } from '@preact/signals-core';
6
5
  import { describe, test } from 'vitest';
7
6
 
8
- import { scheduleTaskInterval } from '@dxos/async';
9
- import { Context } from '@dxos/context';
10
7
  import { Obj } from '@dxos/echo';
11
- import { MemoryQueue } from '@dxos/echo-db';
12
- import { createQueueDXN } from '@dxos/echo-schema';
13
- import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
8
+ import { FunctionExecutor, ServiceContainer } from '@dxos/functions-runtime';
14
9
  import { log } from '@dxos/log';
15
- import { DataType } from '@dxos/schema';
10
+ import { type Actor, Message } from '@dxos/types';
16
11
 
17
- import { MessageNormalizer } from './message-normalizer';
18
12
  import { type MessageWithRangeId, sentenceNormalization } from './normalization';
19
- import { getActorId } from './utils';
20
13
 
21
- const sender: DataType.Actor = {
14
+ const sender: Actor.Actor = {
22
15
  identityDid: 'did:key:123',
23
16
  };
24
17
 
@@ -48,7 +41,7 @@ const messages: MessageWithRangeId[] = [
48
41
  // No punctuation.
49
42
  'in classical physics objects have well-defined properties such as position speed and momentum',
50
43
  ].map((string, index) =>
51
- Obj.make(DataType.Message, {
44
+ Obj.make(Message.Message, {
52
45
  created: new Date(Date.now() + 1_000 * index).toISOString(),
53
46
  sender,
54
47
  blocks: [{ _tag: 'transcript', started: new Date(Date.now() + 1_000 * index).toISOString(), text: string }],
@@ -66,7 +59,7 @@ describe.skip('SentenceNormalization', () => {
66
59
  // ? new Edge AiServiceClient({
67
60
  // endpoint: AI_SERVICE_ENDPOINT.REMOTE,
68
61
  // defaultGenerationOptions: {
69
- // model: '@anthropic/claude-3-5-sonnet-20241022',
62
+ // model: 'ai.claude.model.claude-3-5-sonnet-20241022',
70
63
  // },
71
64
  // })
72
65
  // : new Ollama AiServiceClient({
@@ -99,45 +92,13 @@ describe.skip('SentenceNormalization', () => {
99
92
  }
100
93
 
101
94
  log.info('sentences', {
102
- originalMessages: JSON.stringify(messages, null, 2),
95
+ messages: JSON.stringify(messages, null, 2),
103
96
  sentences: JSON.stringify(sentences, null, 2),
104
97
  });
105
98
  throw new Error('test');
106
99
  });
107
100
 
108
- test.only('queue', { timeout: 120_000 }, async () => {
109
- // Create queue.
110
- // TODO(dmaretskyi): Use space.queues.create() instead.
111
- const queue = new MemoryQueue<DataType.Message>(createQueueDXN());
112
- const ctx = new Context();
113
- let idx = 0;
114
- scheduleTaskInterval(
115
- ctx,
116
- async () => {
117
- if (idx >= messages.length) {
118
- void ctx.dispose();
119
- return;
120
- }
121
- await queue.append([messages[idx]]);
122
- idx++;
123
- },
124
- 2_000,
125
- );
126
-
127
- // Create normalizer.
128
- const normalizer = new MessageNormalizer({
129
- functionExecutor: getExecutor(),
130
- queue,
131
- startingCursor: { actorId: getActorId(sender), timestamp: '0' },
132
- });
133
-
134
- // Start normalizer.
135
- await normalizer.open();
136
- effect(() => {
137
- log.info('normalizer');
138
- log.info(JSON.stringify(queue.objects, null, 2));
139
- });
140
-
141
- await new Promise(() => {});
142
- });
101
+ // TODO(burdon): Restore a Feed-based version once `MessageNormalizer` has a
102
+ // space-backed test fixture available; the previous `MemoryQueue`-based
103
+ // test was incompatible with the `Feed.Feed` + `FeedService` refactor.
143
104
  });
@@ -0,0 +1,76 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import * as Effect from 'effect/Effect';
6
+ import * as Schema from 'effect/Schema';
7
+
8
+ import { Operation } from '@dxos/compute';
9
+ import { log } from '@dxos/log';
10
+ import { trim } from '@dxos/util';
11
+
12
+ import { TranscriptOperation } from '../types';
13
+
14
+ type MessageWithRangeIdType = TranscriptOperation.MessageWithRangeIdType;
15
+ type SentenceNormalizationInputType = TranscriptOperation.SentenceNormalizationInputType;
16
+ const { SentenceNormalization, SentenceNormalizationOutput } = TranscriptOperation;
17
+
18
+ export type MessageWithRangeId = MessageWithRangeIdType;
19
+
20
+ /** @deprecated Use SentenceNormalizationInputType */
21
+ export type NormalizationInput = SentenceNormalizationInputType;
22
+
23
+ /** @deprecated Use SentenceNormalizationOutput */
24
+ export type NormalizationOutput = Schema.Schema.Type<typeof SentenceNormalizationOutput>;
25
+
26
+ /**
27
+ * Sentence normalization for transcription.
28
+ * TODO(dmaretskyi): Reimplement using AiRequest.run or LanguageModel.generateObject - runStructured was removed.
29
+ */
30
+ export const sentenceNormalization = SentenceNormalization.pipe(
31
+ Operation.withHandler(
32
+ Effect.fn(function* ({ messages }) {
33
+ log.info('input', { messages });
34
+ // TODO(dmaretskyi): runStructured was removed from AiRequest. Reimplement using new API.
35
+ return yield* Effect.die(
36
+ new Error(
37
+ 'Sentence normalization needs to be reimplemented - runStructured was removed from AiRequest.Request. Use AiRequest.run or LanguageModel.generateObject.',
38
+ ),
39
+ );
40
+ }),
41
+ ),
42
+ );
43
+
44
+ const _unused = trim`
45
+ You are observing a real-time transcript of a single person speaking.
46
+ The transcription is delivered in chunks of 10 seconds or less. As a result, individual sentences may be split across multiple messages, or multiple sentences may appear within a single message. Additionally, because this is real-time transcription, punctuation and capitalization may be incorrect or missing.
47
+
48
+ # Task Description:
49
+ - Your task is to detect and reconstruct broken or incomplete sentences by merging segments into coherent, grammatically correct sentences where appropriate.
50
+
51
+ # Input Format:
52
+ - The input is an array of messages that contain transcription blocks.
53
+ - Each message is a Message.Message, as described in the output format.
54
+
55
+ # Output Format:
56
+ - You have been provided with the tool that defines the output format; make sure to query it.
57
+ - Do not output anything other than the expected format.
58
+
59
+ # Segment Handling Rules:
60
+ - Sort messages by timestamp.
61
+ - Leave ID of the first message in a sentence.
62
+ - Each divided sentence should be added to the output as a separate message or block within existing messages, preserving the original order.
63
+ - If one message contains multiple sentences, you should not split them.
64
+ - The last sentence may be incomplete; it should still be output as a separate block or message.
65
+ - Keep track of the original timestamps of the messages and blocks and, use the timestamp of the first message/block of a sentence as the 'started' field of the merged message.
66
+ - The 'rangeId' field of the merged message should include 'messageId'-s and 'rangeId'-s of all messages that have been used to construct this message.
67
+
68
+ # Punctuation and Capitalization:
69
+ - Do not rely on the original punctuation and capitalization—they may be incorrect.
70
+ - Use logical reasoning to apply appropriate punctuation (e.g., period, comma, question mark, exclamation mark) and capitalization.
71
+
72
+ # Restrictions:
73
+ - Do not alter the order of the original messages; maintain the natural flow of speech.
74
+ - Do not interpret or infer meaning beyond reconstructing sentences.
75
+ - Do not add or remove any words or phrases.
76
+ `;
@@ -2,8 +2,8 @@
2
2
  // Copyright 2025 DXOS.org
3
3
  //
4
4
 
5
- import { type DataType } from '@dxos/schema';
5
+ import { type Actor } from '@dxos/types';
6
6
 
7
- export const getActorId = (actor: DataType.Actor) => {
7
+ export const getActorId = (actor: Actor.Actor) => {
8
8
  return actor.identityDid || actor.identityKey || actor.email || actor.name || '';
9
9
  };