@dxos/plugin-transcription 0.9.1-main.c7dcc2e112 → 0.10.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 (309) hide show
  1. package/PLUGIN.mdl +5 -5
  2. package/dist/lib/neutral/{TranscriptionArticle-S56VVOSF.mjs → TranscriptionArticle-FEWCWG4A.mjs} +3 -6
  3. package/dist/lib/neutral/TranscriptionArticle-FEWCWG4A.mjs.map +7 -0
  4. package/dist/lib/neutral/TranscriptionPlugin.mjs +25 -4
  5. package/dist/lib/neutral/TranscriptionPlugin.mjs.map +3 -3
  6. package/dist/lib/neutral/TranscriptionPlugin.node.mjs +3 -3
  7. package/dist/lib/neutral/TranscriptionPlugin.node.mjs.map +3 -3
  8. package/dist/lib/neutral/app-graph-builder-GQRMI22E.mjs +48 -0
  9. package/dist/lib/neutral/app-graph-builder-GQRMI22E.mjs.map +7 -0
  10. package/dist/lib/neutral/capabilities/index.mjs +17 -5
  11. package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
  12. package/dist/lib/neutral/{chunk-XZVDAYM6.mjs → chunk-5BVHY75B.mjs} +2 -2
  13. package/dist/lib/neutral/{chunk-XZVDAYM6.mjs.map → chunk-5BVHY75B.mjs.map} +1 -1
  14. package/dist/lib/neutral/chunk-HNXSU7HJ.mjs +8 -0
  15. package/dist/lib/neutral/chunk-KOXLGGSL.mjs +30 -0
  16. package/dist/lib/neutral/chunk-KOXLGGSL.mjs.map +7 -0
  17. package/dist/lib/neutral/{chunk-2URVUJT4.mjs → chunk-MDV7NBFJ.mjs} +31 -8
  18. package/dist/lib/neutral/chunk-MDV7NBFJ.mjs.map +7 -0
  19. package/dist/lib/neutral/components/index.mjs +114 -258
  20. package/dist/lib/neutral/components/index.mjs.map +4 -4
  21. package/dist/lib/neutral/containers/index.mjs +1 -1
  22. package/dist/lib/neutral/{create-7NGOP7JP.mjs → create-HNHGCKZ4.mjs} +2 -2
  23. package/dist/lib/neutral/{enrich-message-F2AOM53F.mjs → enrich-message-DSJU4TXC.mjs} +2 -2
  24. package/dist/lib/neutral/entity-lookup-PCDW7NC4.mjs +25 -0
  25. package/dist/lib/neutral/entity-lookup-PCDW7NC4.mjs.map +7 -0
  26. package/dist/lib/neutral/hooks/index.mjs +93 -15
  27. package/dist/lib/neutral/hooks/index.mjs.map +4 -4
  28. package/dist/lib/neutral/index.mjs +6 -32
  29. package/dist/lib/neutral/markdown-extension-CCDXXY7E.mjs +16 -0
  30. package/dist/lib/neutral/markdown-extension-CCDXXY7E.mjs.map +7 -0
  31. package/dist/lib/neutral/meta.json +1 -1
  32. package/dist/lib/neutral/meta.mjs +1 -1
  33. package/dist/lib/neutral/{open-42H72C4G.mjs → open-SNMZXXYO.mjs} +4 -6
  34. package/dist/lib/neutral/open-SNMZXXYO.mjs.map +7 -0
  35. package/dist/lib/neutral/operations/index.mjs +1 -1
  36. package/dist/lib/neutral/pipeline-status-XMWMAUJY.mjs +17 -0
  37. package/dist/lib/neutral/pipeline-status-XMWMAUJY.mjs.map +7 -0
  38. package/dist/lib/neutral/plugin.mjs +2 -2
  39. package/dist/lib/neutral/recording-session-IADO7ATU.mjs +15 -0
  40. package/dist/lib/neutral/recording-session-IADO7ATU.mjs.map +7 -0
  41. package/dist/lib/neutral/{settings-DUS32HOM.mjs → settings-7KE4MABW.mjs} +3 -2
  42. package/dist/lib/neutral/{settings-DUS32HOM.mjs.map → settings-7KE4MABW.mjs.map} +3 -3
  43. package/dist/lib/neutral/skill-definition-DXNK324V.mjs +15 -0
  44. package/dist/lib/neutral/skill-definition-DXNK324V.mjs.map +7 -0
  45. package/dist/lib/neutral/skills/index.mjs +8 -0
  46. package/dist/lib/neutral/{summarize-45WVUPED.mjs → summarize-LBUZTOTH.mjs} +4 -4
  47. package/dist/lib/neutral/summarize-LBUZTOTH.mjs.map +7 -0
  48. package/dist/lib/neutral/{text-content-XZ3HK4OT.mjs → text-content-NOWR642C.mjs} +2 -4
  49. package/dist/lib/neutral/text-content-NOWR642C.mjs.map +7 -0
  50. package/dist/lib/neutral/transcriber-6XZHUUHK.mjs +174 -0
  51. package/dist/lib/neutral/transcriber-6XZHUUHK.mjs.map +7 -0
  52. package/dist/lib/neutral/transcription-driver-DN6ELQXZ.mjs +207 -0
  53. package/dist/lib/neutral/transcription-driver-DN6ELQXZ.mjs.map +7 -0
  54. package/dist/lib/neutral/translations.mjs +7 -0
  55. package/dist/lib/neutral/translations.mjs.map +2 -2
  56. package/dist/lib/neutral/types/index.mjs +1 -1
  57. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  58. package/dist/types/src/capabilities/app-graph-builder.d.ts +5 -0
  59. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
  60. package/dist/types/src/capabilities/entity-lookup.d.ts +10 -0
  61. package/dist/types/src/capabilities/entity-lookup.d.ts.map +1 -0
  62. package/dist/types/src/capabilities/index.d.ts +7 -1
  63. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  64. package/dist/types/src/capabilities/markdown-extension.d.ts +5 -0
  65. package/dist/types/src/capabilities/markdown-extension.d.ts.map +1 -0
  66. package/dist/types/src/capabilities/pipeline-status.d.ts +9 -0
  67. package/dist/types/src/capabilities/pipeline-status.d.ts.map +1 -0
  68. package/dist/types/src/capabilities/react-surface.d.ts +1 -1
  69. package/dist/types/src/capabilities/recording-session.d.ts +5 -0
  70. package/dist/types/src/capabilities/recording-session.d.ts.map +1 -0
  71. package/dist/types/src/capabilities/settings.d.ts +1 -3
  72. package/dist/types/src/capabilities/settings.d.ts.map +1 -1
  73. package/dist/types/src/capabilities/skill-definition.d.ts +5 -0
  74. package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -0
  75. package/dist/types/src/capabilities/text-content.d.ts +1 -4
  76. package/dist/types/src/capabilities/transcriber.d.ts +4 -3
  77. package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
  78. package/dist/types/src/capabilities/transcription-driver.d.ts +5 -0
  79. package/dist/types/src/capabilities/transcription-driver.d.ts.map +1 -0
  80. package/dist/types/src/components/Mic/Mic.d.ts +12 -0
  81. package/dist/types/src/components/Mic/Mic.d.ts.map +1 -0
  82. package/dist/types/src/components/{Oracle/Oracle.stories.d.ts → Mic/Mic.stories.d.ts} +9 -7
  83. package/dist/types/src/components/Mic/Mic.stories.d.ts.map +1 -0
  84. package/dist/types/src/components/Mic/index.d.ts +2 -0
  85. package/dist/types/src/components/Mic/index.d.ts.map +1 -0
  86. package/dist/types/src/components/index.d.ts +1 -2
  87. package/dist/types/src/components/index.d.ts.map +1 -1
  88. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts.map +1 -1
  89. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts +7 -0
  90. package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts.map +1 -1
  91. package/dist/types/src/hooks/index.d.ts +0 -5
  92. package/dist/types/src/hooks/index.d.ts.map +1 -1
  93. package/dist/types/src/hooks/useTranscriptionRecording.d.ts.map +1 -1
  94. package/dist/types/src/index.d.ts +1 -3
  95. package/dist/types/src/index.d.ts.map +1 -1
  96. package/dist/types/src/meta.d.ts +4 -0
  97. package/dist/types/src/meta.d.ts.map +1 -1
  98. package/dist/types/src/normalization/message-normalizer.d.ts +2 -2
  99. package/dist/types/src/normalization/message-normalizer.d.ts.map +1 -1
  100. package/dist/types/src/normalization/normalization.d.ts +98 -733
  101. package/dist/types/src/normalization/normalization.d.ts.map +1 -1
  102. package/dist/types/src/operations/open.d.ts.map +1 -1
  103. package/dist/types/src/operations/summarize.d.ts.map +1 -1
  104. package/dist/types/src/skills/index.d.ts +2 -0
  105. package/dist/types/src/skills/index.d.ts.map +1 -0
  106. package/dist/types/src/skills/transcription-skill.d.ts +4 -0
  107. package/dist/types/src/skills/transcription-skill.d.ts.map +1 -0
  108. package/dist/types/src/stories/Keyword.stories.d.ts +51 -0
  109. package/dist/types/src/stories/Keyword.stories.d.ts.map +1 -0
  110. package/dist/types/src/stories/Pipeline.stories.d.ts +60 -0
  111. package/dist/types/src/stories/Pipeline.stories.d.ts.map +1 -0
  112. package/dist/types/src/stories/Transcription.stories.d.ts +23 -0
  113. package/dist/types/src/stories/Transcription.stories.d.ts.map +1 -0
  114. package/dist/types/src/testing/decorators.d.ts +21 -0
  115. package/dist/types/src/testing/decorators.d.ts.map +1 -0
  116. package/dist/types/src/testing/index.d.ts +1 -0
  117. package/dist/types/src/testing/index.d.ts.map +1 -1
  118. package/dist/types/src/testing/testing.d.ts +3 -9
  119. package/dist/types/src/testing/testing.d.ts.map +1 -1
  120. package/dist/types/src/{transcriber/transcription-manager.d.ts → transcription-manager.d.ts} +6 -5
  121. package/dist/types/src/transcription-manager.d.ts.map +1 -0
  122. package/dist/types/src/translations.d.ts +7 -0
  123. package/dist/types/src/translations.d.ts.map +1 -1
  124. package/dist/types/src/types/Settings.d.ts +6 -0
  125. package/dist/types/src/types/Settings.d.ts.map +1 -1
  126. package/dist/types/src/types/TranscriptOperation.d.ts +114 -1971
  127. package/dist/types/src/types/TranscriptOperation.d.ts.map +1 -1
  128. package/dist/types/src/types/TranscriptionCapabilities.d.ts +51 -13
  129. package/dist/types/src/types/TranscriptionCapabilities.d.ts.map +1 -1
  130. package/dist/types/src/util/index.d.ts +0 -2
  131. package/dist/types/src/util/index.d.ts.map +1 -1
  132. package/dist/types/tsconfig.tsbuildinfo +1 -1
  133. package/dx.config.ts +1 -1
  134. package/package.json +68 -69
  135. package/src/TranscriptionPlugin.node.ts +2 -2
  136. package/src/TranscriptionPlugin.test.ts +1 -1
  137. package/src/TranscriptionPlugin.tsx +31 -2
  138. package/src/capabilities/app-graph-builder.tsx +49 -0
  139. package/src/capabilities/entity-lookup.ts +32 -0
  140. package/src/capabilities/index.ts +7 -1
  141. package/src/capabilities/markdown-extension.ts +17 -0
  142. package/src/capabilities/pipeline-status.ts +23 -0
  143. package/src/capabilities/recording-session.ts +17 -0
  144. package/src/capabilities/settings.ts +1 -0
  145. package/src/capabilities/skill-definition.ts +15 -0
  146. package/src/capabilities/text-content.ts +1 -2
  147. package/src/capabilities/transcriber.ts +5 -48
  148. package/src/capabilities/transcription-driver.tsx +263 -0
  149. package/src/components/Mic/Mic.stories.tsx +66 -0
  150. package/src/components/Mic/Mic.tsx +136 -0
  151. package/src/components/Mic/index.ts +5 -0
  152. package/src/components/index.ts +1 -2
  153. package/src/containers/TranscriptionArticle/TranscriptionArticle.stories.tsx +4 -0
  154. package/src/containers/TranscriptionArticle/TranscriptionArticle.tsx +4 -5
  155. package/src/hooks/index.ts +0 -5
  156. package/src/hooks/useTranscriptionRecording.ts +4 -8
  157. package/src/index.ts +1 -5
  158. package/src/normalization/message-normalizer.ts +3 -3
  159. package/src/normalization/normalization.ts +3 -0
  160. package/src/operations/open.ts +2 -2
  161. package/src/operations/summarize.ts +2 -2
  162. package/src/skills/index.ts +5 -0
  163. package/src/skills/transcription-skill.ts +29 -0
  164. package/src/stories/Keyword.stories.tsx +98 -0
  165. package/src/stories/Pipeline.stories.tsx +361 -0
  166. package/src/stories/Transcription.stories.tsx +178 -0
  167. package/src/testing/decorators.ts +78 -0
  168. package/src/testing/index.ts +1 -0
  169. package/src/testing/testing.ts +13 -48
  170. package/src/{transcriber/transcription-manager.ts → transcription-manager.ts} +13 -12
  171. package/src/translations.ts +8 -0
  172. package/src/types/Settings.ts +38 -0
  173. package/src/types/TranscriptOperation.ts +6 -4
  174. package/src/types/TranscriptionCapabilities.ts +57 -21
  175. package/src/util/index.ts +0 -2
  176. package/dist/lib/neutral/TranscriptionArticle-S56VVOSF.mjs.map +0 -7
  177. package/dist/lib/neutral/blueprint-definition-DA4QFRYJ.mjs +0 -15
  178. package/dist/lib/neutral/blueprint-definition-DA4QFRYJ.mjs.map +0 -7
  179. package/dist/lib/neutral/blueprints/index.mjs +0 -8
  180. package/dist/lib/neutral/chunk-2URVUJT4.mjs.map +0 -7
  181. package/dist/lib/neutral/chunk-J4ONEYPJ.mjs +0 -8
  182. package/dist/lib/neutral/chunk-MLRJWAQH.mjs +0 -179
  183. package/dist/lib/neutral/chunk-MLRJWAQH.mjs.map +0 -7
  184. package/dist/lib/neutral/chunk-XMHH34NI.mjs +0 -318
  185. package/dist/lib/neutral/chunk-XMHH34NI.mjs.map +0 -7
  186. package/dist/lib/neutral/chunk-XOXHWMXR.mjs +0 -35
  187. package/dist/lib/neutral/chunk-XOXHWMXR.mjs.map +0 -7
  188. package/dist/lib/neutral/chunk-XWC5BBOY.mjs +0 -435
  189. package/dist/lib/neutral/chunk-XWC5BBOY.mjs.map +0 -7
  190. package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs +0 -30
  191. package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs.map +0 -7
  192. package/dist/lib/neutral/open-42H72C4G.mjs.map +0 -7
  193. package/dist/lib/neutral/summarize-45WVUPED.mjs.map +0 -7
  194. package/dist/lib/neutral/text-content-XZ3HK4OT.mjs.map +0 -7
  195. package/dist/lib/neutral/transcriber-KYV6NWI5.mjs +0 -59
  196. package/dist/lib/neutral/transcriber-KYV6NWI5.mjs.map +0 -7
  197. package/dist/types/src/blueprints/index.d.ts +0 -2
  198. package/dist/types/src/blueprints/index.d.ts.map +0 -1
  199. package/dist/types/src/blueprints/transcription-blueprint.d.ts +0 -4
  200. package/dist/types/src/blueprints/transcription-blueprint.d.ts.map +0 -1
  201. package/dist/types/src/capabilities/blueprint-definition.d.ts +0 -6
  202. package/dist/types/src/capabilities/blueprint-definition.d.ts.map +0 -1
  203. package/dist/types/src/components/Oracle/Oracle.d.ts +0 -24
  204. package/dist/types/src/components/Oracle/Oracle.d.ts.map +0 -1
  205. package/dist/types/src/components/Oracle/Oracle.stories.d.ts.map +0 -1
  206. package/dist/types/src/components/Oracle/index.d.ts +0 -2
  207. package/dist/types/src/components/Oracle/index.d.ts.map +0 -1
  208. package/dist/types/src/components/Transcription/Transcription.d.ts +0 -11
  209. package/dist/types/src/components/Transcription/Transcription.d.ts.map +0 -1
  210. package/dist/types/src/components/Transcription/Transcription.stories.d.ts +0 -37
  211. package/dist/types/src/components/Transcription/Transcription.stories.d.ts.map +0 -1
  212. package/dist/types/src/components/Transcription/index.d.ts +0 -2
  213. package/dist/types/src/components/Transcription/index.d.ts.map +0 -1
  214. package/dist/types/src/components/Transcription/transcription-extension.d.ts +0 -15
  215. package/dist/types/src/components/Transcription/transcription-extension.d.ts.map +0 -1
  216. package/dist/types/src/enrichment/conversation.test.d.ts +0 -2
  217. package/dist/types/src/enrichment/conversation.test.d.ts.map +0 -1
  218. package/dist/types/src/enrichment/operations.d.ts +0 -200
  219. package/dist/types/src/enrichment/operations.d.ts.map +0 -1
  220. package/dist/types/src/enrichment/parser.d.ts +0 -26
  221. package/dist/types/src/enrichment/parser.d.ts.map +0 -1
  222. package/dist/types/src/enrichment/stream-simulator.d.ts +0 -38
  223. package/dist/types/src/enrichment/stream-simulator.d.ts.map +0 -1
  224. package/dist/types/src/hooks/useAudioFile.d.ts +0 -7
  225. package/dist/types/src/hooks/useAudioFile.d.ts.map +0 -1
  226. package/dist/types/src/hooks/useAudioTrack.d.ts +0 -5
  227. package/dist/types/src/hooks/useAudioTrack.d.ts.map +0 -1
  228. package/dist/types/src/hooks/useFeedModelAdapter.d.ts +0 -12
  229. package/dist/types/src/hooks/useFeedModelAdapter.d.ts.map +0 -1
  230. package/dist/types/src/hooks/useTranscriber.d.ts +0 -7
  231. package/dist/types/src/hooks/useTranscriber.d.ts.map +0 -1
  232. package/dist/types/src/hooks/useVoiceInput.d.ts +0 -11
  233. package/dist/types/src/hooks/useVoiceInput.d.ts.map +0 -1
  234. package/dist/types/src/model/index.d.ts +0 -2
  235. package/dist/types/src/model/index.d.ts.map +0 -1
  236. package/dist/types/src/model/model.d.ts +0 -68
  237. package/dist/types/src/model/model.d.ts.map +0 -1
  238. package/dist/types/src/model/model.test.d.ts +0 -2
  239. package/dist/types/src/model/model.test.d.ts.map +0 -1
  240. package/dist/types/src/stories/FileTranscription.stories.d.ts +0 -20
  241. package/dist/types/src/stories/FileTranscription.stories.d.ts.map +0 -1
  242. package/dist/types/src/stories/KeyWordRecognition.stories.d.ts +0 -14
  243. package/dist/types/src/stories/KeyWordRecognition.stories.d.ts.map +0 -1
  244. package/dist/types/src/stories/LiveTranscription.stories.d.ts +0 -19
  245. package/dist/types/src/stories/LiveTranscription.stories.d.ts.map +0 -1
  246. package/dist/types/src/stories/ProperNounExtraction.stories.d.ts +0 -13
  247. package/dist/types/src/stories/ProperNounExtraction.stories.d.ts.map +0 -1
  248. package/dist/types/src/stories/TranscriptionStory.d.ts +0 -21
  249. package/dist/types/src/stories/TranscriptionStory.d.ts.map +0 -1
  250. package/dist/types/src/stories/common.d.ts +0 -248
  251. package/dist/types/src/stories/common.d.ts.map +0 -1
  252. package/dist/types/src/transcriber/audio-recorder.d.ts +0 -47
  253. package/dist/types/src/transcriber/audio-recorder.d.ts.map +0 -1
  254. package/dist/types/src/transcriber/index.d.ts +0 -5
  255. package/dist/types/src/transcriber/index.d.ts.map +0 -1
  256. package/dist/types/src/transcriber/media-stream-recorder.d.ts +0 -30
  257. package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +0 -1
  258. package/dist/types/src/transcriber/transcriber.browser.test.d.ts +0 -2
  259. package/dist/types/src/transcriber/transcriber.browser.test.d.ts.map +0 -1
  260. package/dist/types/src/transcriber/transcriber.d.ts +0 -105
  261. package/dist/types/src/transcriber/transcriber.d.ts.map +0 -1
  262. package/dist/types/src/transcriber/transcriber.test.d.ts +0 -2
  263. package/dist/types/src/transcriber/transcriber.test.d.ts.map +0 -1
  264. package/dist/types/src/transcriber/transcription-manager.d.ts.map +0 -1
  265. package/dist/types/src/util/array.d.ts +0 -2
  266. package/dist/types/src/util/array.d.ts.map +0 -1
  267. package/dist/types/src/util/render-byline.d.ts +0 -4
  268. package/dist/types/src/util/render-byline.d.ts.map +0 -1
  269. package/src/blueprints/index.ts +0 -5
  270. package/src/blueprints/transcription-blueprint.ts +0 -29
  271. package/src/capabilities/blueprint-definition.ts +0 -19
  272. package/src/components/Oracle/Oracle.stories.tsx +0 -147
  273. package/src/components/Oracle/Oracle.tsx +0 -142
  274. package/src/components/Oracle/index.ts +0 -5
  275. package/src/components/Transcription/Transcription.stories.tsx +0 -213
  276. package/src/components/Transcription/Transcription.tsx +0 -55
  277. package/src/components/Transcription/index.ts +0 -5
  278. package/src/components/Transcription/transcription-extension.ts +0 -203
  279. package/src/enrichment/conversation.test.ts +0 -162
  280. package/src/enrichment/conversation.txt +0 -23
  281. package/src/enrichment/operations.ts +0 -271
  282. package/src/enrichment/parser.ts +0 -101
  283. package/src/enrichment/stream-simulator.ts +0 -125
  284. package/src/hooks/useAudioFile.ts +0 -88
  285. package/src/hooks/useAudioTrack.ts +0 -35
  286. package/src/hooks/useFeedModelAdapter.ts +0 -46
  287. package/src/hooks/useTranscriber.ts +0 -47
  288. package/src/hooks/useVoiceInput.ts +0 -66
  289. package/src/model/index.ts +0 -5
  290. package/src/model/model.test.ts +0 -175
  291. package/src/model/model.ts +0 -229
  292. package/src/stories/FileTranscription.stories.tsx +0 -143
  293. package/src/stories/KeyWordRecognition.stories.tsx +0 -132
  294. package/src/stories/LiveTranscription.stories.tsx +0 -99
  295. package/src/stories/ProperNounExtraction.stories.tsx +0 -99
  296. package/src/stories/TranscriptionStory.tsx +0 -101
  297. package/src/stories/common.ts +0 -234
  298. package/src/transcriber/audio-recorder.ts +0 -56
  299. package/src/transcriber/index.ts +0 -8
  300. package/src/transcriber/media-stream-recorder.ts +0 -120
  301. package/src/transcriber/transcriber.browser.test.ts +0 -230
  302. package/src/transcriber/transcriber.test.ts +0 -104
  303. package/src/transcriber/transcriber.ts +0 -303
  304. package/src/util/array.ts +0 -14
  305. package/src/util/render-byline.ts +0 -33
  306. /package/dist/lib/neutral/{chunk-J4ONEYPJ.mjs.map → chunk-HNXSU7HJ.mjs.map} +0 -0
  307. /package/dist/lib/neutral/{create-7NGOP7JP.mjs.map → create-HNHGCKZ4.mjs.map} +0 -0
  308. /package/dist/lib/neutral/{enrich-message-F2AOM53F.mjs.map → enrich-message-DSJU4TXC.mjs.map} +0 -0
  309. /package/dist/lib/neutral/{blueprints → skills}/index.mjs.map +0 -0
@@ -0,0 +1,29 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Skill, Template } from '@dxos/compute';
6
+ import { trim } from '@dxos/util';
7
+
8
+ import { TranscriptOperation } from '#types';
9
+
10
+ const SKILL_KEY = 'org.dxos.skill.transcription';
11
+
12
+ const make = () =>
13
+ Skill.make({
14
+ key: SKILL_KEY,
15
+ name: 'Transcription',
16
+ tools: Skill.toolDefinitions({ operations: [TranscriptOperation.Open, TranscriptOperation.Summarize] }),
17
+ instructions: Template.make({
18
+ source: trim`
19
+ You can open and summarize a meeting transcript.
20
+ `,
21
+ }),
22
+ });
23
+
24
+ const skill: Skill.Definition = {
25
+ key: SKILL_KEY,
26
+ make,
27
+ };
28
+
29
+ export default skill;
@@ -0,0 +1,98 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ /**
6
+ * Keyword-spotting demo on the browser's Web Speech API (no DXOS transcriber), driven by the real
7
+ * `Mic` button so the mic UX matches the rest of the suite.
8
+ *
9
+ * - `Default` lists the keywords and checks each as it is heard.
10
+ * - The toolbar `Mic` toggles the shared `RecordingSession`; the story observes it (`useRecordingSession`)
11
+ * to start/stop `window.SpeechRecognition` (continuous + interim results). The editor driver stays
12
+ * idle (no editor view for this session).
13
+ * - Matching normalizes punctuation/whitespace; matched rows show a check via `react-ui-list` `Listbox`.
14
+ */
15
+
16
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
17
+ import React, { useState } from 'react';
18
+
19
+ import { useAtomCapabilityState } from '@dxos/app-framework/ui';
20
+ import { Panel, Toolbar } from '@dxos/react-ui';
21
+ import { Listbox } from '@dxos/react-ui-list';
22
+ import { useSpeechRecognition } from '@dxos/react-ui-transcription';
23
+
24
+ import { Mic } from '#components';
25
+ import { translations } from '#translations';
26
+ import { TranscriptionCapabilities } from '#types';
27
+
28
+ import { createStoryDecorators } from '../testing';
29
+
30
+ // Stable session key for the Mic button; any non-editor id works (the editor driver ignores it).
31
+ const DOC_ID = 'keyword-detection';
32
+
33
+ // Reads the shared recording flag toggled by the `Mic` button (the editor driver stays idle when no
34
+ // editor view is registered for this session).
35
+ const useRecordingSession = (docId: string): boolean => {
36
+ const [session] = useAtomCapabilityState(TranscriptionCapabilities.RecordingSession);
37
+ return !!session?.recording && session.id === docId;
38
+ };
39
+
40
+ type StoryArgs = {
41
+ keywords: string[];
42
+ };
43
+
44
+ const DefaultStory = ({ keywords }: StoryArgs) => {
45
+ const [matched, setMatched] = useState<string | undefined>(undefined);
46
+ const handleTranscript = (transcript: string) => {
47
+ const match = keywords.find((keyword) => transcript.includes(keyword));
48
+ setMatched(match ?? undefined);
49
+ };
50
+
51
+ const recording = useRecordingSession(DOC_ID);
52
+ useSpeechRecognition({ active: recording, onTranscript: handleTranscript });
53
+
54
+ return (
55
+ <Panel.Root>
56
+ <Panel.Toolbar asChild>
57
+ <Toolbar.Root>
58
+ <Mic docId={DOC_ID} />
59
+ </Toolbar.Root>
60
+ </Panel.Toolbar>
61
+
62
+ <Panel.Content>
63
+ <Listbox.Root value={matched}>
64
+ <Listbox.Viewport thin padding>
65
+ <Listbox.Content aria-label='Keywords'>
66
+ {keywords.map((keyword) => (
67
+ <Listbox.Item key={keyword} id={keyword}>
68
+ <Listbox.ItemLabel>{keyword}</Listbox.ItemLabel>
69
+ </Listbox.Item>
70
+ ))}
71
+ </Listbox.Content>
72
+ </Listbox.Viewport>
73
+ </Listbox.Root>
74
+ </Panel.Content>
75
+ </Panel.Root>
76
+ );
77
+ };
78
+
79
+ const meta = {
80
+ title: 'plugins/plugin-transcription/stories/Keyword',
81
+ render: DefaultStory,
82
+ decorators: createStoryDecorators(),
83
+ parameters: {
84
+ layout: 'fullscreen',
85
+ controls: { disable: true },
86
+ translations,
87
+ },
88
+ } satisfies Meta<typeof DefaultStory>;
89
+
90
+ export default meta;
91
+
92
+ type Story = StoryObj<typeof meta>;
93
+
94
+ export const Default: Story = {
95
+ args: {
96
+ keywords: ['hello', 'hey kai', 'kai', 'computer', 'dxos', 'composer'].sort(),
97
+ },
98
+ };
@@ -0,0 +1,361 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ /**
6
+ * End-to-end transcription into a real plugin-markdown editor: the single editor-output integration
7
+ * test, unifying the former MarkdownTranscription, Pipeline and MicPipeline stories.
8
+ *
9
+ * - `Live` — live microphone via the real `TranscriptionDriver` (toolbar `Mic` button), streaming
10
+ * pending text into the document with inline confirm/cancel + entity linking (requires a mic).
11
+ * - `Recording` / `RecordingIndicator` — seed the pending-text decoration (no mic) to show the
12
+ * recording preview / placeholder deterministically.
13
+ * - `CorrectionOnly` / `WithExtraction` / `Full` — drive `PipelineRuntime` over a scripted transcript
14
+ * (correction → extraction → summarization), writing each stage into the doc; status + per-stage
15
+ * telemetry + summary render in the side panel via the shared `PipelineStatus` component.
16
+ * - Space is seeded with Person/Organization entities so extraction links recognized names.
17
+ */
18
+
19
+ import { type StateEffect } from '@codemirror/state';
20
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
21
+ import * as Effect from 'effect/Effect';
22
+ import * as Stream from 'effect/Stream';
23
+ import React, { useEffect, useMemo, useState } from 'react';
24
+
25
+ import { Capability, Plugin } from '@dxos/app-framework';
26
+ import { withPluginManager } from '@dxos/app-framework/testing';
27
+ import { Surface, useAtomCapability, useCapabilities } from '@dxos/app-framework/ui';
28
+ import { AppActivationEvents, AppCapabilities, AppNode, AppPlugin, AppSpace } from '@dxos/app-toolkit';
29
+ import { AppSurface, useAppGraph } from '@dxos/app-toolkit/ui';
30
+ import { Filter, Query } from '@dxos/echo';
31
+ import { Doc } from '@dxos/echo-doc';
32
+ import { EffectEx } from '@dxos/effect';
33
+ import { DXN } from '@dxos/keys';
34
+ import { ClientCapabilities } from '@dxos/plugin-client';
35
+ import { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';
36
+ import { Graph, GraphBuilder, Node, NodeMatcher, qualifyId } from '@dxos/plugin-graph';
37
+ import { Markdown, MarkdownCapabilities, MarkdownEvents } from '@dxos/plugin-markdown';
38
+ import { MarkdownPlugin } from '@dxos/plugin-markdown/testing';
39
+ import { SpacePlugin } from '@dxos/plugin-space/testing';
40
+ import { corePlugins } from '@dxos/plugin-testing';
41
+ import { useQuery, useSpaces } from '@dxos/react-client/echo';
42
+ import { useAttentionAttributes } from '@dxos/react-ui-attention';
43
+ import { PipelineStatus } from '@dxos/react-ui-transcription';
44
+ import { Loading, withLayout } from '@dxos/react-ui/testing';
45
+ import { Text } from '@dxos/schema';
46
+ import {
47
+ type CommitFn,
48
+ PipelineRuntime,
49
+ type Stage,
50
+ type TelemetryEvent,
51
+ TranscriptEvent,
52
+ makeCorrectionStage,
53
+ makeDatabaseLookup,
54
+ makeExtractionStage,
55
+ makeSummarizationStage,
56
+ } from '@dxos/transcription-pipeline';
57
+ import { type ContentBlock, Organization, Person } from '@dxos/types';
58
+ import { seedTestData } from '@dxos/types/testing';
59
+ import { appendPendingText, cancelPendingText, setPendingAnchor, setPendingInterim } from '@dxos/ui-editor';
60
+ import { isNonNullable, trim } from '@dxos/util';
61
+
62
+ import { translations } from '#translations';
63
+ import { TranscriptionCapabilities } from '#types';
64
+
65
+ import { enableQueryIndexes } from '../testing';
66
+ import { TranscriptionPlugin } from '../TranscriptionPlugin';
67
+
68
+ const SAMPLE_CONTENT = trim`
69
+ # Test
70
+
71
+ Place the cursor here, then click the microphone in the toolbar to start recording.
72
+ Live transcription appears inline as greyed text — confirm (✓) to insert it into the document, or cancel (✕) to discard.
73
+
74
+ `;
75
+
76
+ const TRANSCRIPT = trim`
77
+ So I caught up with Sarah Johnson this morning
78
+ We talked about the DXOS and Cyberdyne partnership
79
+ Amco might join the project later this year
80
+ I should follow up with Michael Chen next week
81
+ `.split('\n');
82
+
83
+ // Story-only plugin exposing Markdown documents in the personal space as direct children of the graph
84
+ // root, so TranscriptionPlugin's toolbar extension can attach the record action to the doc's node.
85
+ const StoryGraphPlugin = () =>
86
+ Plugin.define(
87
+ Plugin.makeMeta({
88
+ key: DXN.make('org.dxos.plugin.transcription.story.pipelineGraph'),
89
+ name: 'Transcription Pipeline Story Graph',
90
+ }),
91
+ ).pipe(
92
+ AppPlugin.addAppGraphModule({
93
+ activate: Effect.fnUntraced(function* () {
94
+ const capabilities = yield* Capability.Service;
95
+ const extensions = yield* GraphBuilder.createExtension({
96
+ id: 'storyDocs',
97
+ match: NodeMatcher.whenRoot,
98
+ connector: (_, get) =>
99
+ Effect.gen(function* () {
100
+ // Tolerate the teardown window when stories swap: the Client capability may already be
101
+ // removed while this reactive connector recomputes once more (use `getAll`, not the
102
+ // throwing `get`).
103
+ const [client] = capabilities.getAll(ClientCapabilities.Client);
104
+ const space = client && AppSpace.getPersonalSpace(client);
105
+ if (!space) {
106
+ return [];
107
+ }
108
+
109
+ const docs = get(space.db.query(Filter.type(Markdown.Document)).atom);
110
+ return docs
111
+ .map((object) => AppNode.makeObject({ get, db: space.db, object, droppable: false }))
112
+ .filter(isNonNullable);
113
+ }),
114
+ });
115
+ return Capability.contributes(AppCapabilities.AppGraphBuilder, extensions);
116
+ }),
117
+ }),
118
+ Plugin.make,
119
+ )();
120
+
121
+ type StageId = 'correct' | 'extract' | 'summarize';
122
+ const STAGE_FACTORY: Record<StageId, () => Stage<any, any>> = {
123
+ correct: makeCorrectionStage,
124
+ extract: makeExtractionStage,
125
+ summarize: makeSummarizationStage,
126
+ };
127
+
128
+ type StoryArgs = {
129
+ /**
130
+ * When set, drives `PipelineRuntime` over the scripted transcript through these stages.
131
+ */
132
+ stages?: readonly StageId[];
133
+ /**
134
+ * Seeds the pending-text decoration directly (final/interim), bypassing audio capture, to
135
+ * showcase the recording-state preview deterministically (no microphone).
136
+ */
137
+ seed?: { final?: string; interim?: string };
138
+ };
139
+
140
+ const DefaultStory = ({ stages, seed }: StoryArgs) => {
141
+ const { graph } = useAppGraph();
142
+ const [space] = useSpaces();
143
+ const [doc] = useQuery(space?.db, Query.type(Markdown.Document));
144
+ const attendableId = doc && qualifyId(Node.RootId, doc.id);
145
+ // Mark the editor attended so its toolbar (and the contributed record action) are active.
146
+ const attentionAttrs = useAttentionAttributes(attendableId);
147
+ const [editorViews] = useCapabilities(MarkdownCapabilities.EditorViews);
148
+ const status = useAtomCapability(TranscriptionCapabilities.PipelineStatus);
149
+ const [telemetry, setTelemetry] = useState<TelemetryEvent[]>([]);
150
+ const [summary, setSummary] = useState<string>();
151
+
152
+ // The status panel is relevant for the live (driver phase) and scripted (telemetry) variants; the
153
+ // seeded recording-preview variants are about the inline editor affordance only.
154
+ const showStatus = !seed;
155
+
156
+ // Story renders the surface directly (no deck), so expand the doc node's actions.
157
+ useEffect(() => {
158
+ if (attendableId) {
159
+ void Graph.expand(graph, attendableId, 'action');
160
+ }
161
+ }, [graph, attendableId]);
162
+
163
+ // Seed the pending-text decoration once the editor view has registered (no mic required).
164
+ useEffect(() => {
165
+ if (!attendableId || !editorViews) {
166
+ return;
167
+ }
168
+ // Clear any previously-seeded decoration when seeding stops.
169
+ if (!seed) {
170
+ editorViews.get(attendableId)?.view.dispatch({ effects: cancelPendingText.of() });
171
+ return;
172
+ }
173
+ let cancelled = false;
174
+ const trySeed = () => {
175
+ const entry = editorViews.get(attendableId);
176
+ if (!entry) {
177
+ return false;
178
+ }
179
+ // Anchor the pending block at the end of the document.
180
+ const anchor = entry.view.state.doc.length;
181
+ const effects: StateEffect<unknown>[] = [setPendingAnchor.of({ anchor, placeholder: 'Recording…' })];
182
+ if (seed.final) {
183
+ effects.push(appendPendingText.of(seed.final));
184
+ }
185
+ if (seed.interim) {
186
+ effects.push(setPendingInterim.of(seed.interim));
187
+ }
188
+ entry.view.dispatch({ effects });
189
+ return true;
190
+ };
191
+ if (trySeed()) {
192
+ return;
193
+ }
194
+
195
+ const interval = setInterval(() => {
196
+ if (cancelled || trySeed()) {
197
+ clearInterval(interval);
198
+ }
199
+ }, 50);
200
+ return () => {
201
+ cancelled = true;
202
+ clearInterval(interval);
203
+ };
204
+ }, [seed, attendableId, editorViews]);
205
+
206
+ // Run the pipeline over the scripted transcript, writing each stage's output into the document.
207
+ useEffect(() => {
208
+ const target = doc?.content?.target;
209
+ if (!stages || !space || !target) {
210
+ return;
211
+ }
212
+ let cancelled = false;
213
+ setTelemetry([]);
214
+ setSummary(undefined);
215
+
216
+ const blocks: ContentBlock.Transcript[] = TRANSCRIPT.map((text, index) => ({
217
+ _tag: 'transcript',
218
+ started: new Date(index * 1000).toISOString(),
219
+ text,
220
+ }));
221
+ const stageList = stages.map((id) => STAGE_FACTORY[id]());
222
+
223
+ // Re-render the whole document body from the (mutated-in-place) blocks; preferring corrected text.
224
+ const render = () => {
225
+ const body = blocks.map((block) => block.corrected ?? block.text).join('\n\n');
226
+ Doc.updateText(target, 'content', `# Transcript\n\n${body}\n`);
227
+ };
228
+ render();
229
+
230
+ const commit: CommitFn = (write, window) =>
231
+ Effect.sync(() => {
232
+ if (cancelled) {
233
+ return;
234
+ }
235
+ for (const update of write.blockUpdates ?? []) {
236
+ const block = window[update.index];
237
+ if (block) {
238
+ const { index: _index, ...patch } = update;
239
+ Object.assign(block, patch);
240
+ }
241
+ }
242
+ if (write.transcriptUpdate?.summary) {
243
+ setSummary(write.transcriptUpdate.summary);
244
+ }
245
+ render();
246
+ });
247
+
248
+ const source = Stream.fromIterable([
249
+ ...blocks.map((block) => TranscriptEvent.block(block)),
250
+ TranscriptEvent.silence(5_000),
251
+ ]);
252
+ void EffectEx.runPromise(
253
+ PipelineRuntime.run({
254
+ source,
255
+ stages: stageList,
256
+ lookup: makeDatabaseLookup(space.db),
257
+ commit,
258
+ onTelemetry: (event) => {
259
+ if (!cancelled) {
260
+ setTelemetry((prev) => [...prev, event]);
261
+ }
262
+ },
263
+ }),
264
+ );
265
+
266
+ return () => {
267
+ cancelled = true;
268
+ };
269
+ }, [space, doc, stages]);
270
+
271
+ const data = useMemo(() => ({ subject: doc, attendableId: attendableId ?? 'story' }), [doc, attendableId]);
272
+
273
+ if (!doc) {
274
+ return <Loading data={{ doc: !!doc }} />;
275
+ }
276
+
277
+ if (!showStatus) {
278
+ return (
279
+ <div className='contents' {...attentionAttrs}>
280
+ <Surface.Surface type={AppSurface.Article} data={data} limit={1} />
281
+ </div>
282
+ );
283
+ }
284
+
285
+ return (
286
+ <div role='none' className='dx-container grid grid-cols-[1fr_20rem] gap-2' {...attentionAttrs}>
287
+ <div role='none' className='dx-expander'>
288
+ <Surface.Surface type={AppSurface.Article} data={data} limit={1} />
289
+ </div>
290
+ <PipelineStatus
291
+ phase={stages ? 'idle' : (status?.phase ?? 'idle')}
292
+ stages={stages}
293
+ telemetry={telemetry}
294
+ summary={summary}
295
+ />
296
+ </div>
297
+ );
298
+ };
299
+
300
+ const meta = {
301
+ title: 'plugins/plugin-transcription/stories/Pipeline',
302
+ render: DefaultStory,
303
+ decorators: [
304
+ withLayout({ layout: 'fullscreen' }),
305
+ withPluginManager({
306
+ setupEvents: [AppActivationEvents.SetupSettings, MarkdownEvents.SetupExtensions],
307
+ plugins: [
308
+ ...corePlugins(),
309
+ ClientPlugin({
310
+ types: [Markdown.Document, Text.Text, Person.Person, Organization.Organization],
311
+ onClientInitialized: ({ client }) =>
312
+ Effect.gen(function* () {
313
+ const { personalSpace } = yield* initializeIdentity(client);
314
+ // Vector indexes so extraction can link recognized Person/Organization names.
315
+ yield* enableQueryIndexes(client.services.services);
316
+ yield* Effect.promise(() => seedTestData(personalSpace));
317
+ personalSpace.db.add(Markdown.make({ name: 'Transcript', content: SAMPLE_CONTENT }));
318
+ yield* Effect.promise(() => personalSpace.db.flush({ indexes: true }));
319
+ }),
320
+ }),
321
+ SpacePlugin({}),
322
+ MarkdownPlugin(),
323
+ StoryGraphPlugin(),
324
+ TranscriptionPlugin(),
325
+ ],
326
+ }),
327
+ ],
328
+ parameters: {
329
+ layout: 'fullscreen',
330
+ controls: { disable: true },
331
+ translations,
332
+ },
333
+ } satisfies Meta<typeof DefaultStory>;
334
+
335
+ export default meta;
336
+
337
+ type Story = StoryObj<typeof meta>;
338
+
339
+ /** Live microphone via the real driver: streams transcription into the doc (requires a mic). */
340
+ export const Live: Story = {};
341
+
342
+ /** Scripted: correction only (punctuation / capitalization). */
343
+ export const WithCorrection: Story = {
344
+ args: {
345
+ stages: ['correct'],
346
+ },
347
+ };
348
+
349
+ /** Scripted: correction + entity extraction (recognized entities become dx-anchor links). */
350
+ export const WithExtraction: Story = {
351
+ args: {
352
+ stages: ['correct', 'extract'],
353
+ },
354
+ };
355
+
356
+ /** Scripted: correction + extraction + a cumulative summary (shown in the side panel). */
357
+ export const Full: Story = {
358
+ args: {
359
+ stages: ['correct', 'extract', 'summarize'],
360
+ },
361
+ };
@@ -0,0 +1,178 @@
1
+ //
2
+ // Copyright 2026 DXOS.org
3
+ //
4
+
5
+ /**
6
+ * Streaming file transcription into a message list. Loads an audio file and streams its transcript
7
+ * through the recording engine (Transcriber → runLivePipeline → correction stage) **as it plays** —
8
+ * appending each corrected block as a message rather than waiting for playback to stop.
9
+ *
10
+ * - `Default` plays a hosted m4a; the play/pause + upload toolbar gates playback and capture.
11
+ * - A small chunk threshold drives incremental transcription every few seconds (the streaming stack).
12
+ */
13
+
14
+ import { type Meta, type StoryObj } from '@storybook/react-vite';
15
+ import * as Effect from 'effect/Effect';
16
+ import React, { type ChangeEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
17
+
18
+ import { IconButton, Panel, ScrollContainer, Toolbar } from '@dxos/react-ui';
19
+ import {
20
+ Transcription,
21
+ renderByline,
22
+ useAudioFile,
23
+ useFeedModelAdapter,
24
+ useRecordingPipeline,
25
+ } from '@dxos/react-ui-transcription';
26
+ import { type CommitFn, type TranscribeConfig, makeCorrectionStage } from '@dxos/transcription-pipeline';
27
+ import { type ContentBlock, Message } from '@dxos/types';
28
+
29
+ import { createStoryDecorators } from '../testing';
30
+
31
+ // Small chunk threshold so the transcriber emits every few seconds while the file plays (streaming),
32
+ // instead of only flushing the whole buffer on stop.
33
+ const STREAMING_TRANSCRIBE_CONFIG: Partial<TranscribeConfig> = {
34
+ transcribeAfterChunksAmount: 25,
35
+ prefixBufferChunksAmount: 10,
36
+ };
37
+
38
+ // In-memory message buffer + model adapter (production wires up a real space-backed `Feed`).
39
+ const useStoryMessageModel = () => {
40
+ const [messages, setMessages] = useState<Message.Message[]>([]);
41
+ const appendMessage = useCallback((message: Message.Message) => setMessages((prev) => [...prev, message]), []);
42
+ const model = useFeedModelAdapter(renderByline([]), messages);
43
+ return { model, appendMessage };
44
+ };
45
+
46
+ type StoryArgs = {
47
+ audioUrl: string;
48
+ audioConstraints?: MediaTrackConstraints;
49
+ };
50
+
51
+ const DefaultStory = ({ audioUrl, audioConstraints }: StoryArgs) => {
52
+ // Decode the file/URL into a track; a play/pause button gates playback + capture.
53
+ const [running, setRunning] = useState(false);
54
+ const [uploadedUrl, setUploadedUrl] = useState<string>();
55
+ useEffect(() => {
56
+ return () => {
57
+ if (uploadedUrl) {
58
+ URL.revokeObjectURL(uploadedUrl);
59
+ }
60
+ };
61
+ }, [uploadedUrl]);
62
+
63
+ const fileInputRef = useRef<HTMLInputElement>(null);
64
+ const handleFileChange = useCallback((event: ChangeEvent<HTMLInputElement>) => {
65
+ const file = event.target.files?.[0];
66
+ if (file) {
67
+ setRunning(false);
68
+ setUploadedUrl(URL.createObjectURL(file));
69
+ }
70
+ // Reset so the same file can be re-selected.
71
+ event.target.value = '';
72
+ }, []);
73
+ const { audio, stream, track } = useAudioFile(uploadedUrl ?? audioUrl, audioConstraints);
74
+
75
+ // Pipe the decoded stream into the <audio> element so the user hears playback, mirroring `running`.
76
+ const audioRef = useRef<HTMLAudioElement>(null);
77
+ useEffect(() => {
78
+ if (audioRef.current && stream) {
79
+ audioRef.current.srcObject = stream;
80
+ }
81
+ }, [stream]);
82
+ useEffect(() => {
83
+ if (!audio) {
84
+ return;
85
+ }
86
+ if (running) {
87
+ void audio.play();
88
+ } else {
89
+ audio.pause();
90
+ }
91
+ }, [audio, running]);
92
+
93
+ // Append one message per committed block (keyed by block identity so re-commits don't duplicate).
94
+ const { model, appendMessage } = useStoryMessageModel();
95
+ const seen = useRef(new WeakSet<ContentBlock.Transcript>());
96
+ const commit = useCallback<CommitFn>(
97
+ (write, window) =>
98
+ Effect.sync(() => {
99
+ for (const update of write.blockUpdates ?? []) {
100
+ const block = window[update.index];
101
+ if (!block || seen.current.has(block)) {
102
+ continue;
103
+ }
104
+ seen.current.add(block);
105
+ appendMessage(
106
+ Message.make({
107
+ sender: { name: 'You' },
108
+ created: new Date().toISOString(),
109
+ blocks: [{ ...block, text: update.corrected ?? block.text }],
110
+ }),
111
+ );
112
+ }
113
+ }),
114
+ [appendMessage],
115
+ );
116
+
117
+ const stages = useMemo(() => [makeCorrectionStage()], []);
118
+ useRecordingPipeline({
119
+ config: STREAMING_TRANSCRIBE_CONFIG,
120
+ segmentSentences: true,
121
+ active: running,
122
+ track,
123
+ stages,
124
+ commit,
125
+ });
126
+
127
+ return (
128
+ <>
129
+ <audio ref={audioRef} autoPlay />
130
+ <Panel.Root>
131
+ <Panel.Toolbar asChild>
132
+ <Toolbar.Root>
133
+ <IconButton
134
+ iconOnly
135
+ disabled={!stream}
136
+ icon={running ? 'ph--pause--regular' : 'ph--play--regular'}
137
+ label={running ? 'Pause' : 'Play'}
138
+ onClick={() => setRunning((value) => !value)}
139
+ />
140
+ <input ref={fileInputRef} type='file' accept='audio/*' className='hidden' onChange={handleFileChange} />
141
+ <IconButton
142
+ iconOnly
143
+ icon='ph--upload--regular'
144
+ label='Upload audio'
145
+ onClick={() => fileInputRef.current?.click()}
146
+ />
147
+ </Toolbar.Root>
148
+ </Panel.Toolbar>
149
+ <ScrollContainer.Root pin>
150
+ <Panel.Content asChild>
151
+ <ScrollContainer.Content>
152
+ <ScrollContainer.Viewport>
153
+ <Transcription model={model} />
154
+ </ScrollContainer.Viewport>
155
+ </ScrollContainer.Content>
156
+ </Panel.Content>
157
+ </ScrollContainer.Root>
158
+ </Panel.Root>
159
+ </>
160
+ );
161
+ };
162
+
163
+ const meta = {
164
+ title: 'plugins/plugin-transcription/stories/Transcription',
165
+ render: DefaultStory,
166
+ decorators: createStoryDecorators(),
167
+ } satisfies Meta<StoryArgs>;
168
+
169
+ export default meta;
170
+
171
+ type Story = StoryObj<typeof meta>;
172
+
173
+ export const Default: Story = {
174
+ args: {
175
+ // https://learnenglish.britishcouncil.org/general-english/audio-zone/living-london
176
+ audioUrl: 'https://dxos.network/audio-london.m4a',
177
+ },
178
+ };