@dxos/plugin-transcription 0.8.1 → 0.8.2-main.2f9c567

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 (241) hide show
  1. package/dist/lib/browser/{TranscriptContainer-JQ3HFHLQ.mjs → TranscriptContainer-3LU3XBEB.mjs} +3 -2
  2. package/dist/lib/browser/app-graph-builder-YXELPN6F.mjs +349 -0
  3. package/dist/lib/browser/app-graph-builder-YXELPN6F.mjs.map +7 -0
  4. package/dist/lib/browser/{chunk-YCZISX63.mjs → chunk-GWY2Q2NE.mjs} +108 -81
  5. package/dist/lib/browser/chunk-GWY2Q2NE.mjs.map +7 -0
  6. package/dist/lib/browser/chunk-HNIKXVCG.mjs +720 -0
  7. package/dist/lib/browser/chunk-HNIKXVCG.mjs.map +7 -0
  8. package/dist/lib/browser/chunk-HRDAILQX.mjs +27 -0
  9. package/dist/lib/browser/chunk-HRDAILQX.mjs.map +7 -0
  10. package/dist/lib/browser/{chunk-GU2BNYKZ.mjs → chunk-KLD7O5GJ.mjs} +2 -12
  11. package/dist/lib/browser/chunk-KLD7O5GJ.mjs.map +7 -0
  12. package/dist/lib/browser/{chunk-YEPT334A.mjs → chunk-LTIQFX4W.mjs} +1 -1
  13. package/dist/lib/browser/chunk-LTIQFX4W.mjs.map +7 -0
  14. package/dist/lib/browser/chunk-TGOKX32G.mjs +63 -0
  15. package/dist/lib/browser/chunk-TGOKX32G.mjs.map +7 -0
  16. package/dist/lib/browser/index.mjs +46 -209
  17. package/dist/lib/browser/index.mjs.map +4 -4
  18. package/dist/lib/browser/{intent-resolver-4R66ZCKT.mjs → intent-resolver-BBB3DWV4.mjs} +8 -8
  19. package/dist/lib/browser/intent-resolver-BBB3DWV4.mjs.map +7 -0
  20. package/dist/lib/browser/{meeting-transcription-state-DLFHQK72.mjs → meeting-transcription-state-MNA2XROE.mjs} +4 -4
  21. package/dist/lib/browser/meeting-transcription-state-MNA2XROE.mjs.map +7 -0
  22. package/dist/lib/browser/meta.json +1 -1
  23. package/dist/lib/browser/{react-surface-FQUHU5G7.mjs → react-surface-R277DACJ.mjs} +18 -6
  24. package/dist/lib/browser/react-surface-R277DACJ.mjs.map +7 -0
  25. package/dist/lib/browser/settings-I226DZ27.mjs +24 -0
  26. package/dist/lib/browser/settings-I226DZ27.mjs.map +7 -0
  27. package/dist/lib/browser/{transcriber-LGMIWDYI.mjs → transcriber-QRSS6X6S.mjs} +8 -7
  28. package/dist/lib/browser/{transcriber-LGMIWDYI.mjs.map → transcriber-QRSS6X6S.mjs.map} +3 -3
  29. package/dist/lib/browser/types/index.mjs +3 -3
  30. package/dist/lib/node/{TranscriptContainer-QEYTTT2V.cjs → TranscriptContainer-DICOMZLM.cjs} +8 -7
  31. package/dist/lib/node/TranscriptContainer-DICOMZLM.cjs.map +7 -0
  32. package/dist/lib/node/app-graph-builder-I6LYVIYY.cjs +350 -0
  33. package/dist/lib/node/app-graph-builder-I6LYVIYY.cjs.map +7 -0
  34. package/dist/lib/node/{chunk-P4VVD6ZO.cjs → chunk-34WFY7M7.cjs} +24 -34
  35. package/dist/lib/node/chunk-34WFY7M7.cjs.map +7 -0
  36. package/dist/lib/node/chunk-4JOJCZPJ.cjs +737 -0
  37. package/dist/lib/node/chunk-4JOJCZPJ.cjs.map +7 -0
  38. package/dist/lib/node/{chunk-3KHUSQNW.cjs → chunk-J72PUQ3C.cjs} +6 -15
  39. package/dist/lib/node/chunk-J72PUQ3C.cjs.map +7 -0
  40. package/dist/lib/node/{chunk-CZMLKKWT.cjs → chunk-JUGOXWES.cjs} +4 -4
  41. package/dist/lib/node/chunk-JUGOXWES.cjs.map +7 -0
  42. package/dist/lib/node/{chunk-LP4FG423.cjs → chunk-K553L7CZ.cjs} +23 -8
  43. package/dist/lib/node/chunk-K553L7CZ.cjs.map +7 -0
  44. package/dist/lib/node/{chunk-FCCJALOT.cjs → chunk-RK4BEN5E.cjs} +111 -83
  45. package/dist/lib/node/chunk-RK4BEN5E.cjs.map +7 -0
  46. package/dist/lib/node/index.cjs +65 -237
  47. package/dist/lib/node/index.cjs.map +4 -4
  48. package/dist/lib/node/{intent-resolver-WMMCOUEH.cjs → intent-resolver-7XY3WITN.cjs} +11 -10
  49. package/dist/lib/node/intent-resolver-7XY3WITN.cjs.map +7 -0
  50. package/dist/lib/node/{meeting-transcription-state-URIYILEQ.cjs → meeting-transcription-state-5XLTMWPA.cjs} +7 -7
  51. package/dist/lib/node/meeting-transcription-state-5XLTMWPA.cjs.map +7 -0
  52. package/dist/lib/node/meta.json +1 -1
  53. package/dist/lib/node/{react-surface-WI2MGWCC.cjs → react-surface-HUSWAORU.cjs} +20 -10
  54. package/dist/lib/node/react-surface-HUSWAORU.cjs.map +7 -0
  55. package/dist/lib/node/settings-NDMU3EWQ.cjs +38 -0
  56. package/dist/lib/node/settings-NDMU3EWQ.cjs.map +7 -0
  57. package/dist/lib/node/{transcriber-QG5WPKX4.cjs → transcriber-UZJMG44C.cjs} +14 -13
  58. package/dist/lib/node/{transcriber-QG5WPKX4.cjs.map → transcriber-UZJMG44C.cjs.map} +3 -3
  59. package/dist/lib/node/types/index.cjs +8 -8
  60. package/dist/lib/node/types/index.cjs.map +1 -1
  61. package/dist/lib/node-esm/{TranscriptContainer-ZXUCOWGY.mjs → TranscriptContainer-K4E4P5T6.mjs} +3 -2
  62. package/dist/lib/node-esm/app-graph-builder-6FY2UQOH.mjs +350 -0
  63. package/dist/lib/node-esm/app-graph-builder-6FY2UQOH.mjs.map +7 -0
  64. package/dist/lib/node-esm/chunk-3I7AC3D3.mjs +28 -0
  65. package/dist/lib/node-esm/chunk-3I7AC3D3.mjs.map +7 -0
  66. package/dist/lib/node-esm/{chunk-PTZHDZ36.mjs → chunk-5E2MR5XK.mjs} +1 -1
  67. package/dist/lib/node-esm/chunk-5E2MR5XK.mjs.map +7 -0
  68. package/dist/lib/node-esm/chunk-6C34FO4C.mjs +721 -0
  69. package/dist/lib/node-esm/chunk-6C34FO4C.mjs.map +7 -0
  70. package/dist/lib/node-esm/{chunk-YQYBLFNI.mjs → chunk-CKANLRS4.mjs} +108 -81
  71. package/dist/lib/node-esm/chunk-CKANLRS4.mjs.map +7 -0
  72. package/dist/lib/node-esm/chunk-KUQ3ZTRX.mjs +64 -0
  73. package/dist/lib/node-esm/chunk-KUQ3ZTRX.mjs.map +7 -0
  74. package/dist/lib/node-esm/{chunk-HKATMD34.mjs → chunk-QMHMEKB3.mjs} +2 -12
  75. package/dist/lib/node-esm/chunk-QMHMEKB3.mjs.map +7 -0
  76. package/dist/lib/node-esm/index.mjs +46 -209
  77. package/dist/lib/node-esm/index.mjs.map +4 -4
  78. package/dist/lib/node-esm/{intent-resolver-QN2LO5TX.mjs → intent-resolver-ACGAPLDZ.mjs} +8 -8
  79. package/dist/lib/node-esm/intent-resolver-ACGAPLDZ.mjs.map +7 -0
  80. package/dist/lib/node-esm/{meeting-transcription-state-ZYVRAW6Y.mjs → meeting-transcription-state-3WOZ52BQ.mjs} +4 -4
  81. package/dist/lib/node-esm/meeting-transcription-state-3WOZ52BQ.mjs.map +7 -0
  82. package/dist/lib/node-esm/meta.json +1 -1
  83. package/dist/lib/node-esm/{react-surface-PCH6NTVB.mjs → react-surface-G2OY4MWL.mjs} +18 -6
  84. package/dist/lib/node-esm/react-surface-G2OY4MWL.mjs.map +7 -0
  85. package/dist/lib/node-esm/settings-O7X2UQQG.mjs +25 -0
  86. package/dist/lib/node-esm/settings-O7X2UQQG.mjs.map +7 -0
  87. package/dist/lib/node-esm/{transcriber-TMPYZ5L4.mjs → transcriber-NVVFH7IF.mjs} +8 -7
  88. package/dist/lib/node-esm/{transcriber-TMPYZ5L4.mjs.map → transcriber-NVVFH7IF.mjs.map} +3 -3
  89. package/dist/lib/node-esm/types/index.mjs +3 -3
  90. package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
  91. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  92. package/dist/types/src/capabilities/capabilities.d.ts +5 -7
  93. package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
  94. package/dist/types/src/capabilities/index.d.ts +2 -4
  95. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  96. package/dist/types/src/capabilities/meeting-transcription-state.d.ts +2 -4
  97. package/dist/types/src/capabilities/meeting-transcription-state.d.ts.map +1 -1
  98. package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
  99. package/dist/types/src/capabilities/settings.d.ts +4 -0
  100. package/dist/types/src/capabilities/settings.d.ts.map +1 -0
  101. package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
  102. package/dist/types/src/components/Transcript/Transcript.d.ts +14 -4
  103. package/dist/types/src/components/Transcript/Transcript.d.ts.map +1 -1
  104. package/dist/types/src/components/Transcript/Transcript.stories.d.ts +19 -4
  105. package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +1 -1
  106. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +27 -0
  107. package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +1 -0
  108. package/dist/types/src/components/Transcript/transcript-extension.d.ts +19 -0
  109. package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +1 -0
  110. package/dist/types/src/components/TranscriptContainer.d.ts.map +1 -1
  111. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts +6 -0
  112. package/dist/types/src/components/TranscriptionSettings/TranscriptionSettings.d.ts.map +1 -0
  113. package/dist/types/src/components/TranscriptionSettings/index.d.ts +2 -0
  114. package/dist/types/src/components/TranscriptionSettings/index.d.ts.map +1 -0
  115. package/dist/types/src/components/index.d.ts +1 -0
  116. package/dist/types/src/components/index.d.ts.map +1 -1
  117. package/dist/types/src/components/transcription.stories.d.ts +6 -3
  118. package/dist/types/src/components/transcription.stories.d.ts.map +1 -1
  119. package/dist/types/src/entity-extraction/entity-extraction.d.ts +42 -0
  120. package/dist/types/src/entity-extraction/entity-extraction.d.ts.map +1 -0
  121. package/dist/types/src/entity-extraction/entity-extraction.test.d.ts +2 -0
  122. package/dist/types/src/entity-extraction/entity-extraction.test.d.ts.map +1 -0
  123. package/dist/types/src/entity-extraction/index.d.ts +2 -0
  124. package/dist/types/src/entity-extraction/index.d.ts.map +1 -0
  125. package/dist/types/src/hooks/index.d.ts +1 -0
  126. package/dist/types/src/hooks/index.d.ts.map +1 -1
  127. package/dist/types/src/hooks/useQueueModelAdapter.d.ts +7 -0
  128. package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +1 -0
  129. package/dist/types/src/hooks/useTranscriber.d.ts +1 -1
  130. package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
  131. package/dist/types/src/model/index.d.ts +2 -0
  132. package/dist/types/src/model/index.d.ts.map +1 -0
  133. package/dist/types/src/model/model.d.ts +68 -0
  134. package/dist/types/src/model/model.d.ts.map +1 -0
  135. package/dist/types/src/model/model.test.d.ts +2 -0
  136. package/dist/types/src/model/model.test.d.ts.map +1 -0
  137. package/dist/types/src/testing/index.d.ts +2 -0
  138. package/dist/types/src/testing/index.d.ts.map +1 -0
  139. package/dist/types/src/testing/testing.d.ts +40 -0
  140. package/dist/types/src/testing/testing.d.ts.map +1 -0
  141. package/dist/types/src/transcriber/transcriber.browser.test.d.ts +2 -0
  142. package/dist/types/src/transcriber/transcriber.browser.test.d.ts.map +1 -0
  143. package/dist/types/src/transcriber/transcriber.d.ts +2 -2
  144. package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
  145. package/dist/types/src/transcriber/transcription-manager.d.ts +17 -15
  146. package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
  147. package/dist/types/src/translations.d.ts +3 -0
  148. package/dist/types/src/translations.d.ts.map +1 -1
  149. package/dist/types/src/types/schema.d.ts +26 -40
  150. package/dist/types/src/types/schema.d.ts.map +1 -1
  151. package/dist/types/src/types/types.d.ts +11 -7
  152. package/dist/types/src/types/types.d.ts.map +1 -1
  153. package/dist/types/src/util/index.d.ts +0 -1
  154. package/dist/types/src/util/index.d.ts.map +1 -1
  155. package/package.json +53 -40
  156. package/src/TranscriptionPlugin.tsx +29 -12
  157. package/src/capabilities/app-graph-builder.ts +111 -52
  158. package/src/capabilities/capabilities.ts +4 -3
  159. package/src/capabilities/index.ts +1 -0
  160. package/src/capabilities/intent-resolver.ts +5 -5
  161. package/src/capabilities/meeting-transcription-state.ts +2 -2
  162. package/src/capabilities/react-surface.tsx +12 -4
  163. package/src/capabilities/settings.ts +20 -0
  164. package/src/capabilities/transcriber.ts +2 -1
  165. package/src/components/Transcript/Transcript.stories.tsx +201 -43
  166. package/src/components/Transcript/Transcript.tsx +83 -208
  167. package/src/components/Transcript/deprecated/OldTranscript.tsx +260 -0
  168. package/src/components/Transcript/transcript-extension.ts +236 -0
  169. package/src/components/TranscriptContainer.tsx +11 -6
  170. package/src/components/TranscriptionSettings/TranscriptionSettings.tsx +26 -0
  171. package/src/components/TranscriptionSettings/index.ts +5 -0
  172. package/src/components/index.ts +1 -0
  173. package/src/components/transcription.stories.tsx +163 -60
  174. package/src/entity-extraction/entity-extraction.test.ts +97 -0
  175. package/src/entity-extraction/entity-extraction.ts +149 -0
  176. package/src/entity-extraction/index.ts +5 -0
  177. package/src/entity-extraction/system-prompt.tpl +38 -0
  178. package/src/entity-extraction/types.d.ts +8 -0
  179. package/src/hooks/index.ts +1 -0
  180. package/src/hooks/useQueueModelAdapter.ts +63 -0
  181. package/src/hooks/useTranscriber.ts +3 -2
  182. package/src/model/index.ts +5 -0
  183. package/src/model/model.test.ts +169 -0
  184. package/src/model/model.ts +229 -0
  185. package/src/testing/index.ts +5 -0
  186. package/src/testing/testing.ts +221 -0
  187. package/src/transcriber/{transcriber.test.ts → transcriber.browser.test.ts} +3 -3
  188. package/src/transcriber/transcriber.ts +20 -11
  189. package/src/transcriber/transcription-manager.ts +67 -58
  190. package/src/translations.ts +2 -0
  191. package/src/types/schema.ts +11 -32
  192. package/src/types/types.ts +19 -9
  193. package/src/util/index.ts +0 -1
  194. package/dist/lib/browser/app-graph-builder-VDQOVX7P.mjs +0 -191
  195. package/dist/lib/browser/app-graph-builder-VDQOVX7P.mjs.map +0 -7
  196. package/dist/lib/browser/chunk-G4B6CPC2.mjs +0 -253
  197. package/dist/lib/browser/chunk-G4B6CPC2.mjs.map +0 -7
  198. package/dist/lib/browser/chunk-GU2BNYKZ.mjs.map +0 -7
  199. package/dist/lib/browser/chunk-K7FOYAXO.mjs +0 -8
  200. package/dist/lib/browser/chunk-K7FOYAXO.mjs.map +0 -7
  201. package/dist/lib/browser/chunk-OGNXNGJB.mjs +0 -73
  202. package/dist/lib/browser/chunk-OGNXNGJB.mjs.map +0 -7
  203. package/dist/lib/browser/chunk-YCZISX63.mjs.map +0 -7
  204. package/dist/lib/browser/chunk-YEPT334A.mjs.map +0 -7
  205. package/dist/lib/browser/intent-resolver-4R66ZCKT.mjs.map +0 -7
  206. package/dist/lib/browser/meeting-transcription-state-DLFHQK72.mjs.map +0 -7
  207. package/dist/lib/browser/react-surface-FQUHU5G7.mjs.map +0 -7
  208. package/dist/lib/node/TranscriptContainer-QEYTTT2V.cjs.map +0 -7
  209. package/dist/lib/node/app-graph-builder-IFSIVNUR.cjs +0 -200
  210. package/dist/lib/node/app-graph-builder-IFSIVNUR.cjs.map +0 -7
  211. package/dist/lib/node/chunk-3KHUSQNW.cjs.map +0 -7
  212. package/dist/lib/node/chunk-CZMLKKWT.cjs.map +0 -7
  213. package/dist/lib/node/chunk-FCCJALOT.cjs.map +0 -7
  214. package/dist/lib/node/chunk-LP4FG423.cjs.map +0 -7
  215. package/dist/lib/node/chunk-P4VVD6ZO.cjs.map +0 -7
  216. package/dist/lib/node/chunk-UOFHT4GZ.cjs +0 -280
  217. package/dist/lib/node/chunk-UOFHT4GZ.cjs.map +0 -7
  218. package/dist/lib/node/intent-resolver-WMMCOUEH.cjs.map +0 -7
  219. package/dist/lib/node/meeting-transcription-state-URIYILEQ.cjs.map +0 -7
  220. package/dist/lib/node/react-surface-WI2MGWCC.cjs.map +0 -7
  221. package/dist/lib/node-esm/app-graph-builder-UL6XLIZY.mjs +0 -192
  222. package/dist/lib/node-esm/app-graph-builder-UL6XLIZY.mjs.map +0 -7
  223. package/dist/lib/node-esm/chunk-6X7X2UZF.mjs +0 -254
  224. package/dist/lib/node-esm/chunk-6X7X2UZF.mjs.map +0 -7
  225. package/dist/lib/node-esm/chunk-GIO6J6FE.mjs +0 -74
  226. package/dist/lib/node-esm/chunk-GIO6J6FE.mjs.map +0 -7
  227. package/dist/lib/node-esm/chunk-HKATMD34.mjs.map +0 -7
  228. package/dist/lib/node-esm/chunk-J4D2RBBH.mjs +0 -10
  229. package/dist/lib/node-esm/chunk-J4D2RBBH.mjs.map +0 -7
  230. package/dist/lib/node-esm/chunk-PTZHDZ36.mjs.map +0 -7
  231. package/dist/lib/node-esm/chunk-YQYBLFNI.mjs.map +0 -7
  232. package/dist/lib/node-esm/intent-resolver-QN2LO5TX.mjs.map +0 -7
  233. package/dist/lib/node-esm/meeting-transcription-state-ZYVRAW6Y.mjs.map +0 -7
  234. package/dist/lib/node-esm/react-surface-PCH6NTVB.mjs.map +0 -7
  235. package/dist/types/src/transcriber/transcriber.test.d.ts +0 -2
  236. package/dist/types/src/transcriber/transcriber.test.d.ts.map +0 -1
  237. package/dist/types/src/util/random-queue-dxn.d.ts +0 -3
  238. package/dist/types/src/util/random-queue-dxn.d.ts.map +0 -1
  239. package/src/util/random-queue-dxn.ts +0 -9
  240. /package/dist/lib/browser/{TranscriptContainer-JQ3HFHLQ.mjs.map → TranscriptContainer-3LU3XBEB.mjs.map} +0 -0
  241. /package/dist/lib/node-esm/{TranscriptContainer-ZXUCOWGY.mjs.map → TranscriptContainer-K4E4P5T6.mjs.map} +0 -0
@@ -16,84 +16,148 @@ import React, {
16
16
  useState,
17
17
  } from 'react';
18
18
 
19
- import { createStatic } from '@dxos/echo-schema';
19
+ import { Events, IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
20
+ import { withPluginManager } from '@dxos/app-framework/testing';
21
+ import { AIServiceEdgeClient } from '@dxos/assistant';
22
+ import { AI_SERVICE_ENDPOINT } from '@dxos/assistant/testing';
23
+ import { Filter, MemoryQueue } from '@dxos/echo-db';
24
+ import { create } from '@dxos/echo-schema';
20
25
  import { type DXN } from '@dxos/keys';
21
26
  import { log } from '@dxos/log';
22
- import { Config } from '@dxos/react-client';
23
- import { useQueue } from '@dxos/react-client/echo';
24
- import { withClientProvider } from '@dxos/react-client/testing';
27
+ import { ClientPlugin } from '@dxos/plugin-client';
28
+ import { PreviewPlugin } from '@dxos/plugin-preview';
29
+ import { SpacePlugin } from '@dxos/plugin-space';
30
+ import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
31
+ import { ThemePlugin } from '@dxos/plugin-theme';
32
+ import { createQueueDxn, useQueue, useSpace } from '@dxos/react-client/echo';
25
33
  import { IconButton, Toolbar } from '@dxos/react-ui';
26
34
  import { ScrollContainer } from '@dxos/react-ui-components';
35
+ import { defaultTx } from '@dxos/react-ui-theme';
36
+ import { DataType } from '@dxos/schema';
37
+ import { seedTestData, Testing } from '@dxos/schema/testing';
27
38
  import { withLayout, withTheme } from '@dxos/storybook-utils';
28
39
 
29
- import { Transcript } from './Transcript';
30
- import { useAudioFile, useAudioTrack, useTranscriber } from '../hooks';
40
+ import { renderMarkdown, Transcript } from './Transcript';
41
+ import { TranscriptionPlugin } from '../TranscriptionPlugin';
42
+ import { processTranscriptMessage } from '../entity-extraction';
43
+ import { useAudioFile, useAudioTrack, useQueueModelAdapter, useTranscriber } from '../hooks';
44
+ import { type SerializationModel } from '../model';
45
+ import { TestItem } from '../testing';
31
46
  import { type TranscriberParams } from '../transcriber';
32
- import { TranscriptBlock } from '../types';
33
- import { randomQueueDxn } from '../util';
34
47
 
35
48
  const TranscriptionStory: FC<{
36
- playing: boolean;
37
- setPlaying: Dispatch<SetStateAction<boolean>>;
38
- blocks?: TranscriptBlock[];
39
- }> = ({ playing, setPlaying, blocks }) => {
49
+ model: SerializationModel<DataType.Message>;
50
+ running: boolean;
51
+ onRunningChange: Dispatch<SetStateAction<boolean>>;
52
+ }> = ({ model, running, onRunningChange }) => {
53
+ const space = useSpace();
54
+
40
55
  return (
41
56
  <div className='flex flex-col w-[30rem]'>
42
57
  <Toolbar.Root>
43
58
  <IconButton
44
59
  iconOnly
45
- icon={playing ? 'ph--pause--regular' : 'ph--play--regular'}
46
- label={playing ? 'Pause' : 'Play'}
47
- onClick={() => setPlaying((playing) => !playing)}
60
+ icon={running ? 'ph--pause--regular' : 'ph--play--regular'}
61
+ label={running ? 'Pause' : 'Play'}
62
+ onClick={() => onRunningChange((running) => !running)}
48
63
  />
49
64
  </Toolbar.Root>
50
65
  <ScrollContainer>
51
- <Transcript blocks={blocks} attendableId='story' />
66
+ <Transcript space={space} model={model} attendableId='story' />
52
67
  </ScrollContainer>
53
68
  </div>
54
69
  );
55
70
  };
56
71
 
57
- const Microphone = () => {
58
- const [playing, setPlaying] = useState(false);
72
+ const aiService = new AIServiceEdgeClient({
73
+ endpoint: AI_SERVICE_ENDPOINT.REMOTE,
74
+ });
75
+
76
+ const Microphone = ({ entityExtraction }: { entityExtraction?: boolean }) => {
77
+ const [running, setRunning] = useState(false);
59
78
 
60
79
  // Audio.
61
- const track = useAudioTrack(playing);
80
+ const track = useAudioTrack(running);
62
81
 
63
82
  // Queue.
64
- const queueDxn = useMemo(() => randomQueueDxn(), []);
65
- const queue = useQueue<TranscriptBlock>(queueDxn, { pollInterval: 500 });
83
+ const queueDxn = useMemo(() => createQueueDxn(), []);
84
+ const queue = useMemo(() => new MemoryQueue<DataType.Message>(queueDxn), [queueDxn]);
85
+ const model = useQueueModelAdapter(renderMarkdown([]), queue);
86
+ const space = useSpace();
66
87
 
67
88
  // Transcriber.
68
89
  const handleSegments = useCallback<TranscriberParams['onSegments']>(
69
- async (segments) => {
70
- const block = createStatic(TranscriptBlock, { segments });
71
- queue?.append([block]);
90
+ async (blocks) => {
91
+ const message = create(DataType.Message, { sender: { name: 'You' }, created: new Date().toISOString(), blocks });
92
+
93
+ if (entityExtraction) {
94
+ if (!space) {
95
+ log.warn('no space');
96
+ return;
97
+ }
98
+ // TODO(dmaretskyi): Move to vector search index.
99
+ const { objects } = await space.db
100
+ .query(
101
+ Filter.or(
102
+ Filter.schema(DataType.Person),
103
+ Filter.schema(DataType.Organization),
104
+ Filter.schema(Testing.DocumentType),
105
+ ),
106
+ )
107
+ .run();
108
+
109
+ log.info('context', { objects });
110
+
111
+ const result = await processTranscriptMessage({
112
+ message,
113
+ aiService,
114
+ context: {
115
+ objects,
116
+ },
117
+ options: {
118
+ fallbackToRaw: true,
119
+ },
120
+ });
121
+ void queue.append([result.message]);
122
+ } else {
123
+ void queue.append([message]);
124
+ }
72
125
  },
73
- [queue],
126
+ [queue, space],
74
127
  );
75
- const transcriber = useTranscriber({ audioStreamTrack: track, onSegments: handleSegments });
128
+
129
+ const config = useRef<TranscriberParams['config']>({
130
+ transcribeAfterChunksAmount: 20,
131
+ prefixBufferChunksAmount: 5,
132
+ });
133
+
134
+ const transcriber = useTranscriber({
135
+ audioStreamTrack: track,
136
+ onSegments: handleSegments,
137
+ config: config.current,
138
+ });
139
+ const [isOpen, setIsOpen] = useState(false);
76
140
  useEffect(() => {
77
- void transcriber?.open();
141
+ void transcriber?.open().then(() => setIsOpen(true));
78
142
  return () => {
79
- void transcriber?.close();
143
+ void transcriber?.close().then(() => setIsOpen(false));
80
144
  };
81
145
  }, [transcriber]);
82
146
 
83
147
  // Manage transcription state.
84
148
  useEffect(() => {
85
- if (playing && transcriber?.isOpen) {
86
- void transcriber?.startChunksRecording();
87
- } else if (!playing) {
88
- void transcriber?.stopChunksRecording();
149
+ if (running && transcriber?.isOpen) {
150
+ transcriber?.startChunksRecording();
151
+ } else if (!running) {
152
+ transcriber?.stopChunksRecording();
89
153
  }
90
- }, [transcriber, playing, transcriber?.isOpen]);
154
+ }, [transcriber, running, isOpen]);
91
155
 
92
- return <TranscriptionStory playing={playing} setPlaying={setPlaying} blocks={queue?.items} />;
156
+ return <TranscriptionStory model={model} running={running} onRunningChange={setRunning} />;
93
157
  };
94
158
 
95
159
  const AudioFile = ({ queueDxn, audioUrl }: { queueDxn: DXN; audioUrl: string; transcriptUrl: string }) => {
96
- const [playing, setPlaying] = useState(false);
160
+ const [running, setRunning] = useState(false);
97
161
 
98
162
  // Audio.
99
163
  const audioElement = useRef<HTMLAudioElement>(null);
@@ -110,19 +174,20 @@ const AudioFile = ({ queueDxn, audioUrl }: { queueDxn: DXN; audioUrl: string; tr
110
174
  return;
111
175
  }
112
176
 
113
- if (playing) {
177
+ if (running) {
114
178
  void audio.play();
115
179
  } else {
116
180
  void audio.pause();
117
181
  }
118
- }, [audio, playing]);
182
+ }, [audio, running]);
119
183
 
120
184
  // Transcriber.
121
- const queue = useQueue<TranscriptBlock>(queueDxn, { pollInterval: 500 });
185
+ const queue = useQueue<DataType.Message>(queueDxn, { pollInterval: 500 });
186
+ const model = useQueueModelAdapter(renderMarkdown([]), queue);
122
187
  const handleSegments = useCallback<TranscriberParams['onSegments']>(
123
- async (segments) => {
124
- const block = createStatic(TranscriptBlock, { authorName: 'test', authorHue: 'cyan', segments });
125
- queue?.append([block]);
188
+ async (blocks) => {
189
+ const message = create(DataType.Message, { sender: { name: 'You' }, created: new Date().toISOString(), blocks });
190
+ void queue?.append([message]);
126
191
  },
127
192
  [queue],
128
193
  );
@@ -133,15 +198,15 @@ const AudioFile = ({ queueDxn, audioUrl }: { queueDxn: DXN; audioUrl: string; tr
133
198
  });
134
199
 
135
200
  useEffect(() => {
136
- if (transcriber && playing) {
137
- void transcriber.open();
138
- } else if (!playing) {
201
+ if (transcriber && running) {
202
+ void transcriber.open().then(manageChunkRecording);
203
+ } else if (!running) {
139
204
  transcriber?.stopChunksRecording();
140
205
  void transcriber?.close();
141
206
  }
142
- }, [transcriber, playing]);
207
+ }, [transcriber, running]);
143
208
 
144
- useEffect(() => {
209
+ const manageChunkRecording = () => {
145
210
  if (track?.readyState === 'live' && transcriber?.isOpen) {
146
211
  log.info('starting transcription');
147
212
  transcriber.startChunksRecording();
@@ -149,24 +214,54 @@ const AudioFile = ({ queueDxn, audioUrl }: { queueDxn: DXN; audioUrl: string; tr
149
214
  log.info('stopping transcription');
150
215
  transcriber.stopChunksRecording();
151
216
  }
217
+ };
218
+ useEffect(() => {
219
+ manageChunkRecording();
152
220
  }, [transcriber, track?.readyState, transcriber?.isOpen]);
153
221
 
154
- return <TranscriptionStory playing={playing} setPlaying={setPlaying} blocks={queue?.items} />;
222
+ return <TranscriptionStory model={model} running={running} onRunningChange={setRunning} />;
155
223
  };
156
224
 
157
225
  const meta: Meta<typeof AudioFile> = {
158
226
  title: 'plugins/plugin-transcription/transcription',
159
227
  decorators: [
160
- withClientProvider({
161
- config: new Config({
162
- runtime: {
163
- client: { edgeFeatures: { signaling: true } },
164
- services: {
165
- edge: { url: 'https://edge.dxos.workers.dev/' },
166
- iceProviders: [{ urls: 'https://edge.dxos.workers.dev/ice' }],
228
+ withPluginManager({
229
+ plugins: [
230
+ ThemePlugin({ tx: defaultTx }),
231
+ StorybookLayoutPlugin(),
232
+ ClientPlugin({
233
+ types: [TestItem, DataType.Person, DataType.Organization, Testing.DocumentType],
234
+ onClientInitialized: async (_, client) => {
235
+ await client.halo.createIdentity();
236
+ await client.spaces.waitUntilReady();
237
+ await client.spaces.default.waitUntilReady();
238
+ await seedTestData(client.spaces.default);
167
239
  },
168
- },
169
- }),
240
+ }),
241
+ SpacePlugin(),
242
+ SettingsPlugin(),
243
+ PreviewPlugin(),
244
+ IntentPlugin(),
245
+ TranscriptionPlugin(),
246
+ ],
247
+ fireEvents: [Events.SetupAppGraph],
248
+ // capabilities: [
249
+ // contributes(
250
+ // Capabilities.ReactSurface,
251
+ // createSurface({
252
+ // id: 'preview-test',
253
+ // role: 'preview',
254
+ // component: ({ data }) => {
255
+ // const schema = getSchema(data);
256
+ // if (!schema) {
257
+ // return null;
258
+ // }
259
+
260
+ // return <Form schema={schema} values={data} />;
261
+ // },
262
+ // }),
263
+ // ),
264
+ // ],
170
265
  }),
171
266
  withTheme,
172
267
  withLayout({
@@ -179,16 +274,24 @@ const meta: Meta<typeof AudioFile> = {
179
274
 
180
275
  export default meta;
181
276
 
182
- type Story = StoryObj<typeof AudioFile>;
277
+ export const Default: StoryObj<typeof Microphone> = {
278
+ render: Microphone,
279
+ args: {
280
+ entityExtraction: false,
281
+ },
282
+ };
183
283
 
184
- export const Default: Story = {
284
+ export const EntityExtraction: StoryObj<typeof Microphone> = {
185
285
  render: Microphone,
286
+ args: {
287
+ entityExtraction: true,
288
+ },
186
289
  };
187
290
 
188
- export const File: Story = {
291
+ export const File: StoryObj<typeof AudioFile> = {
189
292
  render: AudioFile,
190
293
  args: {
191
- queueDxn: randomQueueDxn(),
294
+ queueDxn: createQueueDxn(),
192
295
  // https://learnenglish.britishcouncil.org/general-english/audio-zone/living-london
193
296
  transcriptUrl: 'https://dxos.network/audio-london.txt',
194
297
  audioUrl: 'https://dxos.network/audio-london.m4a',
@@ -0,0 +1,97 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { describe, test, expect } from 'vitest';
6
+
7
+ import { AIServiceEdgeClient } from '@dxos/assistant';
8
+ import { AI_SERVICE_ENDPOINT } from '@dxos/assistant/testing';
9
+ import { log } from '@dxos/log';
10
+ import { createTestData } from '@dxos/schema/testing';
11
+ import { range } from '@dxos/util';
12
+
13
+ import { processTranscriptMessage, postprocessText } from './entity-extraction';
14
+
15
+ const aiService = new AIServiceEdgeClient({
16
+ endpoint: AI_SERVICE_ENDPOINT.REMOTE,
17
+ });
18
+
19
+ describe.skip('EntityExtraction', { timeout: 180_000 }, () => {
20
+ test.skip('should process a transcript block', async () => {
21
+ const { transcriptMessages, documents, contacts } = await createTestData();
22
+
23
+ log.info('context', { documents, contacts });
24
+
25
+ for (const message of transcriptMessages) {
26
+ log.info('input', message);
27
+ const { message: enhancedMessage } = await processTranscriptMessage({
28
+ message,
29
+ aiService,
30
+ context: {
31
+ objects: [...documents, ...Object.values(contacts)],
32
+ },
33
+ });
34
+ log.info('output', enhancedMessage);
35
+ }
36
+ });
37
+
38
+ test.only('computational irreducibility', async () => {
39
+ const { transcriptWoflram, documents, contacts } = await createTestData();
40
+
41
+ log.info('context', { documents, contacts });
42
+ const message = transcriptWoflram[0];
43
+ log.info('input', message);
44
+
45
+ await Promise.all(
46
+ range(10).map(async () => {
47
+ const { message: enhancedMessage, timeElapsed } = await processTranscriptMessage({
48
+ message,
49
+ aiService,
50
+ context: {
51
+ objects: [...documents, ...Object.values(contacts)],
52
+ },
53
+ });
54
+ log.info('output', { message: enhancedMessage.blocks[0], timeElapsed });
55
+ }),
56
+ );
57
+ });
58
+
59
+ test('org and document linking', async () => {
60
+ const { transcriptJosiah, documents, contacts, organizations } = await createTestData();
61
+
62
+ log.info('context', { contacts, organizations, documents });
63
+
64
+ for (const message of transcriptJosiah) {
65
+ log.info('input', message);
66
+
67
+ const { message: enhancedMessage } = await processTranscriptMessage({
68
+ message,
69
+ aiService,
70
+ context: {
71
+ objects: [...documents, ...Object.values(contacts), ...Object.values(organizations)],
72
+ },
73
+ });
74
+ log.info('output', enhancedMessage);
75
+ }
76
+ });
77
+ });
78
+
79
+ describe('postprocessText', () => {
80
+ test('should replace quotes with DXN references', () => {
81
+ const quotes = {
82
+ references: [{ quote: 'computational irreducibility', id: '01JTG9JW11XGWJZ32AW8ET93D1' }],
83
+ };
84
+
85
+ expect(postprocessText('This is a computational irreducibility test.', quotes)).toBe(
86
+ 'This is a [computational irreducibility][dxn:echo:@:01JTG9JW11XGWJZ32AW8ET93D1] test.',
87
+ );
88
+ expect(
89
+ postprocessText(
90
+ "And what I'd like to talk today about is Steven Wolfram's concept of a computational irreducibility.",
91
+ quotes,
92
+ ),
93
+ ).toBe(
94
+ "And what I'd like to talk today about is Steven Wolfram's concept of a [computational irreducibility][dxn:echo:@:01JTG9JW11XGWJZ32AW8ET93D1].",
95
+ );
96
+ });
97
+ });
@@ -0,0 +1,149 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ import { Schema } from 'effect';
6
+
7
+ import { createTemplate, Message, structuredOutputParser } from '@dxos/artifact';
8
+ import type { AIServiceClient } from '@dxos/assistant';
9
+ import { MixedStreamParser } from '@dxos/assistant';
10
+ import { asyncTimeout } from '@dxos/async';
11
+ import { type BaseEchoObject, create, ObjectId } from '@dxos/echo-schema';
12
+ import { DXN } from '@dxos/keys';
13
+ import { log } from '@dxos/log';
14
+ import { DataType } from '@dxos/schema';
15
+
16
+ import SYSTEM_PROMPT from './system-prompt.tpl?raw';
17
+
18
+ type ProcessTranscriptMessageParams = {
19
+ message: DataType.Message;
20
+ aiService: AIServiceClient;
21
+ context: {
22
+ objects?: BaseEchoObject[];
23
+ };
24
+
25
+ options?: {
26
+ /**
27
+ * Timeout for the entity extraction.
28
+ */
29
+ timeout?: number;
30
+
31
+ /**
32
+ * Fallback to raw text if the entity extraction fails.
33
+ * Otherwise the function will throw an error.
34
+ * @default false
35
+ */
36
+ fallbackToRaw?: boolean;
37
+ };
38
+ };
39
+
40
+ type ProcessTranscriptMessageResult = {
41
+ message: DataType.Message;
42
+ timeElapsed: number;
43
+ };
44
+
45
+ /**
46
+ * Process Handlebars template.
47
+ */
48
+ const createSystemPrompt = (): string => {
49
+ const template = createTemplate(SYSTEM_PROMPT);
50
+ return template({});
51
+ };
52
+
53
+ const ReferencedQuotes = Schema.Struct({
54
+ references: Schema.Array(
55
+ Schema.Struct({
56
+ quote: Schema.String,
57
+ id: Schema.String,
58
+ }),
59
+ ).annotations({
60
+ description:
61
+ 'The references to the context objects that are mentioned in the transcript. quote should match the original transcript text exactly, while id is the id of the context object.',
62
+ }),
63
+ });
64
+ interface ReferencedQuotes extends Schema.Schema.Type<typeof ReferencedQuotes> {}
65
+
66
+ // TODO(dmaretskyi): Move context to a vector search index.
67
+ export const processTranscriptMessage = async (
68
+ params: ProcessTranscriptMessageParams,
69
+ ): Promise<ProcessTranscriptMessageResult> => {
70
+ try {
71
+ const outputParser = structuredOutputParser(ReferencedQuotes);
72
+ const runParser = async (): Promise<ProcessTranscriptMessageResult> => {
73
+ const startTime = performance.now();
74
+ const result = outputParser.getResult(
75
+ await new MixedStreamParser().parse(
76
+ await params.aiService.execStream({
77
+ model: '@anthropic/claude-3-5-haiku-20241022',
78
+ systemPrompt: createSystemPrompt(),
79
+ history: [
80
+ create(Message, {
81
+ role: 'user',
82
+ content: [
83
+ {
84
+ type: 'text',
85
+ text: `<context>${JSON.stringify(params.context.objects)}</context>`,
86
+ },
87
+ {
88
+ type: 'text',
89
+ text: `<transcript>${JSON.stringify(params.message.blocks)}</transcript>`,
90
+ },
91
+ ],
92
+ }),
93
+ ],
94
+ tools: [outputParser.tool],
95
+ }),
96
+ ),
97
+ );
98
+ log.info('entity extraction result', { refs: result.references });
99
+
100
+ return {
101
+ message: create(DataType.Message, {
102
+ ...params.message,
103
+ blocks: params.message.blocks.map((block, i) =>
104
+ block.type !== 'transcription'
105
+ ? block
106
+ : {
107
+ ...block,
108
+ text: postprocessText(block.text, result),
109
+ },
110
+ ),
111
+ }),
112
+ timeElapsed: performance.now() - startTime,
113
+ };
114
+ };
115
+
116
+ if (params.options?.timeout && params.options.timeout > 0) {
117
+ return await asyncTimeout(runParser(), params.options.timeout);
118
+ } else {
119
+ return await runParser();
120
+ }
121
+ } catch (error) {
122
+ if (params.options?.fallbackToRaw) {
123
+ log.warn('failed to process transcript message, falling back to raw text', { error });
124
+ return {
125
+ message: params.message,
126
+ timeElapsed: 0,
127
+ };
128
+ } else {
129
+ throw error;
130
+ }
131
+ }
132
+ };
133
+
134
+ /**
135
+ * Finds and replaces all quotes with DXNs references.
136
+ */
137
+ // TODO(dmaretskyi): Lookup and verifiy ids from provided context.
138
+ export const postprocessText = (text: string, quotes: ReferencedQuotes) => {
139
+ for (const quote of quotes.references) {
140
+ if (!ObjectId.isValid(quote.id)) {
141
+ continue;
142
+ }
143
+
144
+ // Use a case-insensitive regular expression to replace the quote
145
+ const regex = new RegExp(quote.quote.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
146
+ text = text.replace(regex, `[${quote.quote}][${DXN.fromLocalObjectId(quote.id).toString()}]`);
147
+ }
148
+ return text;
149
+ };
@@ -0,0 +1,5 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ export * from './entity-extraction';
@@ -0,0 +1,38 @@
1
+ You are an AI assistant specialized in processing and enhancing transcripts with contextual information.
2
+ Your task is to analyze a given transcript and extract references to the context objects.
3
+
4
+ The context and transcript are provided in the user message in `context` and `transcript` XML tags.
5
+
6
+ Here are your instructions:
7
+
8
+ 1. Read the transcript and context information provided above.
9
+
10
+ 2. Process each segment of the transcript separately.
11
+
12
+ 3. For each segment:
13
+ a. Analyze the content and identify relevant information from the context.
14
+ b. Extract a number of references to the context objects that are mentioned in the segment.
15
+ c. Output the references in the format `{ "quote": "earnings report", "id": "01JT0JP9AX0XKGZX4MV4B69VT6" }`.
16
+ d. If there are no references, just output an empty array.
17
+
18
+ 4. Maintain the exact order and structure of the original transcript segments.
19
+
20
+ Output Format:
21
+ The final output should be a JSON array of references.
22
+
23
+ Example output structure:
24
+ ```json
25
+ {
26
+ "references": [
27
+ { "quote": "earnings report", "id": "01JT0JP9AX0XKGZX4MV4B69VT6" },
28
+ { "quote": "John", "id": "01JT0VM0VN3ZKN7GDBM8CV9BA7" }
29
+ ]
30
+ }
31
+ ```
32
+
33
+ Remember:
34
+ - Only quote the text that is in the transcript.
35
+ - Analyze each segment carefully before processing it.
36
+ - Only reference objects that appear in the context and exactly by their id, If the object is not in the context, do not insert a reference.
37
+
38
+ Now, process the transcript and context provided below according to these instructions.
@@ -0,0 +1,8 @@
1
+ //
2
+ // Copyright 2025 DXOS.org
3
+ //
4
+
5
+ declare module '*.tpl?raw' {
6
+ const content: string;
7
+ export default content;
8
+ }
@@ -4,5 +4,6 @@
4
4
 
5
5
  export * from './useAudioFile';
6
6
  export * from './useAudioTrack';
7
+ export * from './useQueueModelAdapter';
7
8
  export * from './useTranscriber';
8
9
  export * from './useVoiceInput';