@dxos/plugin-transcription 0.8.4-main.ae835ea → 0.8.4-main.bc2380dfbc
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.
- package/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/neutral/TranscriptionArticle-L6XANBH5.mjs +54 -0
- package/dist/lib/neutral/TranscriptionArticle-L6XANBH5.mjs.map +7 -0
- package/dist/lib/neutral/TranscriptionPlugin.mjs +34 -0
- package/dist/lib/neutral/TranscriptionPlugin.mjs.map +7 -0
- package/dist/lib/neutral/TranscriptionPlugin.node.mjs +25 -0
- package/dist/lib/neutral/TranscriptionPlugin.node.mjs.map +7 -0
- package/dist/lib/neutral/TranscriptionPlugin.workerd.mjs +21 -0
- package/dist/lib/neutral/TranscriptionPlugin.workerd.mjs.map +7 -0
- package/dist/lib/neutral/blueprint-definition-HOXDG5QP.mjs +15 -0
- package/dist/lib/neutral/blueprint-definition-HOXDG5QP.mjs.map +7 -0
- package/dist/lib/neutral/blueprints/index.mjs +8 -0
- package/dist/lib/neutral/capabilities/index.mjs +17 -0
- package/dist/lib/neutral/capabilities/index.mjs.map +7 -0
- package/dist/lib/neutral/chunk-2O3ONPRZ.mjs +298 -0
- package/dist/lib/neutral/chunk-2O3ONPRZ.mjs.map +7 -0
- package/dist/lib/neutral/chunk-5FXU36PN.mjs +120 -0
- package/dist/lib/neutral/chunk-5FXU36PN.mjs.map +7 -0
- package/dist/lib/{browser/chunk-VBUIO677.mjs → neutral/chunk-GL4RS533.mjs} +2 -9
- package/dist/lib/neutral/chunk-GL4RS533.mjs.map +7 -0
- package/dist/lib/{browser/chunk-WH36ENNE.mjs → neutral/chunk-ILSA3DU7.mjs} +102 -133
- package/dist/lib/neutral/chunk-ILSA3DU7.mjs.map +7 -0
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +10 -0
- package/dist/lib/neutral/chunk-KAEXRX3Y.mjs +35 -0
- package/dist/lib/neutral/chunk-KAEXRX3Y.mjs.map +7 -0
- package/dist/lib/neutral/chunk-MLRJWAQH.mjs +179 -0
- package/dist/lib/neutral/chunk-MLRJWAQH.mjs.map +7 -0
- package/dist/lib/neutral/chunk-Y5EQAFFR.mjs +8 -0
- package/dist/lib/neutral/chunk-Y5EQAFFR.mjs.map +7 -0
- package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs +30 -0
- package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +272 -0
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/containers/index.mjs +9 -0
- package/dist/lib/neutral/containers/index.mjs.map +7 -0
- package/dist/lib/neutral/create-RRWRIUSR.mjs +21 -0
- package/dist/lib/neutral/create-RRWRIUSR.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +19 -0
- package/dist/lib/neutral/index.mjs +44 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +8 -0
- package/dist/lib/neutral/meta.mjs.map +7 -0
- package/dist/lib/neutral/open-CVMX5KXZ.mjs +27 -0
- package/dist/lib/neutral/open-CVMX5KXZ.mjs.map +7 -0
- package/dist/lib/neutral/operation-handler-NXMOAXFP.mjs +13 -0
- package/dist/lib/neutral/operation-handler-NXMOAXFP.mjs.map +7 -0
- package/dist/lib/neutral/operations/index.mjs +8 -0
- package/dist/lib/neutral/operations/index.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +16 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/react-surface-YMZRO242.mjs +26 -0
- package/dist/lib/neutral/react-surface-YMZRO242.mjs.map +7 -0
- package/dist/lib/neutral/summarize-LA7TRW7A.mjs +78 -0
- package/dist/lib/neutral/summarize-LA7TRW7A.mjs.map +7 -0
- package/dist/lib/neutral/text-content-F4ASMITB.mjs +30 -0
- package/dist/lib/neutral/text-content-F4ASMITB.mjs.map +7 -0
- package/dist/lib/{node-esm/transcriber-UGB7ECX6.mjs → neutral/transcriber-ABHATBVH.mjs} +20 -18
- package/dist/lib/neutral/transcriber-ABHATBVH.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +24 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/lib/neutral/types/index.mjs +10 -0
- package/dist/lib/neutral/types/index.mjs.map +7 -0
- package/dist/types/src/TranscriptionPlugin.d.ts +3 -1
- package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
- package/dist/types/src/TranscriptionPlugin.node.d.ts +4 -0
- package/dist/types/src/TranscriptionPlugin.node.d.ts.map +1 -0
- package/dist/types/src/TranscriptionPlugin.test.d.ts +2 -0
- package/dist/types/src/TranscriptionPlugin.test.d.ts.map +1 -0
- package/dist/types/src/TranscriptionPlugin.workerd.d.ts +4 -0
- package/dist/types/src/TranscriptionPlugin.workerd.d.ts.map +1 -0
- package/dist/types/src/blueprints/index.d.ts +2 -0
- package/dist/types/src/blueprints/index.d.ts.map +1 -0
- package/dist/types/src/blueprints/transcription-blueprint.d.ts +4 -0
- package/dist/types/src/blueprints/transcription-blueprint.d.ts.map +1 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -4
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +10 -5
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/operation-handler.d.ts +6 -0
- package/dist/types/src/capabilities/operation-handler.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +3 -2
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/text-content.d.ts +8 -0
- package/dist/types/src/capabilities/text-content.d.ts.map +1 -0
- package/dist/types/src/capabilities/transcriber.d.ts +4 -3
- package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
- package/dist/types/src/components/Oracle/Oracle.d.ts +24 -0
- package/dist/types/src/components/Oracle/Oracle.d.ts.map +1 -0
- package/dist/types/src/components/Oracle/Oracle.stories.d.ts +32 -0
- package/dist/types/src/components/Oracle/Oracle.stories.d.ts.map +1 -0
- package/dist/types/src/components/Oracle/index.d.ts +2 -0
- package/dist/types/src/components/Oracle/index.d.ts.map +1 -0
- package/dist/types/src/components/Transcription/Transcription.d.ts +13 -0
- package/dist/types/src/components/Transcription/Transcription.d.ts.map +1 -0
- package/dist/types/src/components/Transcription/Transcription.stories.d.ts +37 -0
- package/dist/types/src/components/Transcription/Transcription.stories.d.ts.map +1 -0
- package/dist/types/src/components/Transcription/index.d.ts +2 -0
- package/dist/types/src/components/Transcription/index.d.ts.map +1 -0
- package/dist/types/src/components/Transcription/transcription-extension.d.ts +15 -0
- package/dist/types/src/components/Transcription/transcription-extension.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +2 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts +6 -0
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts.map +1 -0
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts +28 -0
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts.map +1 -0
- package/dist/types/src/containers/TranscriptionArticle/index.d.ts +2 -0
- package/dist/types/src/containers/TranscriptionArticle/index.d.ts.map +1 -0
- package/dist/types/src/containers/index.d.ts +3 -0
- package/dist/types/src/containers/index.d.ts.map +1 -0
- package/dist/types/src/enrichment/conversation.test.d.ts +2 -0
- package/dist/types/src/enrichment/conversation.test.d.ts.map +1 -0
- package/dist/types/src/enrichment/operations.d.ts +200 -0
- package/dist/types/src/enrichment/operations.d.ts.map +1 -0
- package/dist/types/src/enrichment/parser.d.ts +26 -0
- package/dist/types/src/enrichment/parser.d.ts.map +1 -0
- package/dist/types/src/enrichment/stream-simulator.d.ts +38 -0
- package/dist/types/src/enrichment/stream-simulator.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +2 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
- package/dist/types/src/hooks/useAudioTrack.d.ts.map +1 -1
- package/dist/types/src/hooks/useFeedModelAdapter.d.ts +12 -0
- package/dist/types/src/hooks/useFeedModelAdapter.d.ts.map +1 -0
- package/dist/types/src/hooks/useTranscriber.d.ts +2 -2
- package/dist/types/src/hooks/useTranscriber.d.ts.map +1 -1
- package/dist/types/src/hooks/useTranscriptionRecording.d.ts +12 -0
- package/dist/types/src/hooks/useTranscriptionRecording.d.ts.map +1 -0
- package/dist/types/src/hooks/useVoiceInput.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +2 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -2
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/model/model.d.ts +2 -2
- package/dist/types/src/model/model.d.ts.map +1 -1
- package/dist/types/src/{segments-normalization → normalization}/index.d.ts +1 -1
- package/dist/types/src/normalization/index.d.ts.map +1 -0
- package/dist/types/src/{segments-normalization → normalization}/message-normalizer.d.ts +9 -7
- package/dist/types/src/normalization/message-normalizer.d.ts.map +1 -0
- package/dist/types/src/normalization/normalization.d.ts +543 -0
- package/dist/types/src/normalization/normalization.d.ts.map +1 -0
- package/dist/types/src/normalization/normalization.test.d.ts.map +1 -0
- package/dist/types/src/normalization/utils.d.ts +3 -0
- package/dist/types/src/normalization/utils.d.ts.map +1 -0
- package/dist/types/src/operations/create.d.ts +5 -0
- package/dist/types/src/operations/create.d.ts.map +1 -0
- package/dist/types/src/operations/index.d.ts +3 -0
- package/dist/types/src/operations/index.d.ts.map +1 -0
- package/dist/types/src/operations/open.d.ts +5 -0
- package/dist/types/src/operations/open.d.ts.map +1 -0
- package/dist/types/src/operations/summarize.d.ts +8 -0
- package/dist/types/src/operations/summarize.d.ts.map +1 -0
- package/dist/types/src/plugin.d.ts +4 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/stories/FileTranscription.stories.d.ts +20 -0
- package/dist/types/src/stories/FileTranscription.stories.d.ts.map +1 -0
- package/dist/types/src/{components/stories → stories}/KeyWordRecognition.stories.d.ts +2 -2
- package/dist/types/src/stories/KeyWordRecognition.stories.d.ts.map +1 -0
- package/dist/types/src/{components/stories/MicrophoneTranscription.stories.d.ts → stories/LiveTranscription.stories.d.ts} +7 -7
- package/dist/types/src/stories/LiveTranscription.stories.d.ts.map +1 -0
- package/dist/types/src/stories/TranscriptionStory.d.ts +21 -0
- package/dist/types/src/stories/TranscriptionStory.d.ts.map +1 -0
- package/dist/types/src/stories/common.d.ts +46 -0
- package/dist/types/src/stories/common.d.ts.map +1 -0
- package/dist/types/src/testing/testing.d.ts +13 -14
- package/dist/types/src/testing/testing.d.ts.map +1 -1
- package/dist/types/src/transcriber/index.d.ts +1 -1
- package/dist/types/src/transcriber/index.d.ts.map +1 -1
- package/dist/types/src/transcriber/media-stream-recorder.d.ts +2 -2
- package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +1 -1
- package/dist/types/src/transcriber/transcriber.d.ts +61 -6
- package/dist/types/src/transcriber/transcriber.d.ts.map +1 -1
- package/dist/types/src/transcriber/transcriber.test.d.ts +2 -0
- package/dist/types/src/transcriber/transcriber.test.d.ts.map +1 -0
- package/dist/types/src/transcriber/transcription-manager.d.ts +14 -9
- package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +9 -8
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/TranscriptOperation.d.ts +917 -0
- package/dist/types/src/types/TranscriptOperation.d.ts.map +1 -0
- package/dist/types/src/types/TranscriptionCapabilities.d.ts +17 -0
- package/dist/types/src/types/TranscriptionCapabilities.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -3
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/util/array.d.ts.map +1 -1
- package/dist/types/src/util/get-time-str.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/monitor-audio-level.d.ts.map +1 -1
- package/dist/types/src/util/render-byline.d.ts +4 -0
- package/dist/types/src/util/render-byline.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +157 -82
- package/src/TranscriptionPlugin.node.ts +20 -0
- package/src/TranscriptionPlugin.test.ts +31 -0
- package/src/TranscriptionPlugin.tsx +20 -64
- package/src/TranscriptionPlugin.workerd.ts +18 -0
- package/src/blueprints/index.ts +5 -0
- package/src/blueprints/transcription-blueprint.ts +29 -0
- package/src/capabilities/blueprint-definition.ts +12 -24
- package/src/capabilities/index.ts +11 -7
- package/src/capabilities/operation-handler.ts +16 -0
- package/src/capabilities/react-surface.tsx +23 -14
- package/src/capabilities/text-content.ts +33 -0
- package/src/capabilities/transcriber.ts +53 -42
- package/src/components/Oracle/Oracle.stories.tsx +147 -0
- package/src/components/Oracle/Oracle.tsx +141 -0
- package/src/components/Oracle/index.ts +5 -0
- package/src/components/Transcription/Transcription.stories.tsx +213 -0
- package/src/components/Transcription/Transcription.tsx +58 -0
- package/src/components/{Transcript → Transcription}/index.ts +1 -1
- package/src/components/{Transcript/transcript-extension.ts → Transcription/transcription-extension.ts} +13 -9
- package/src/components/index.ts +2 -6
- package/src/containers/TranscriptionArticle/TranscriptionArticle.stories.tsx +61 -0
- package/src/containers/TranscriptionArticle/TranscriptionArticle.tsx +62 -0
- package/src/containers/TranscriptionArticle/index.ts +5 -0
- package/src/containers/index.ts +7 -0
- package/src/enrichment/conversation.test.ts +162 -0
- package/src/enrichment/conversation.txt +23 -0
- package/src/enrichment/operations.ts +268 -0
- package/src/enrichment/parser.ts +101 -0
- package/src/enrichment/stream-simulator.ts +125 -0
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useFeedModelAdapter.ts +46 -0
- package/src/hooks/useTranscriber.ts +12 -4
- package/src/hooks/useTranscriptionRecording.ts +87 -0
- package/src/hooks/useVoiceInput.ts +2 -3
- package/src/index.ts +4 -5
- package/src/meta.ts +3 -3
- package/src/model/model.test.ts +20 -14
- package/src/model/model.ts +3 -3
- package/src/{segments-normalization → normalization}/message-normalizer.ts +37 -24
- package/src/{segments-normalization → normalization}/normalization.test.ts +8 -47
- package/src/normalization/normalization.ts +76 -0
- package/src/{segments-normalization → normalization}/utils.ts +2 -2
- package/src/operations/create.ts +24 -0
- package/src/operations/index.ts +11 -0
- package/src/operations/open.ts +28 -0
- package/src/operations/summarize.ts +101 -0
- package/src/plugin.ts +11 -0
- package/src/stories/FileTranscription.stories.tsx +143 -0
- package/src/{components/stories → stories}/KeyWordRecognition.stories.tsx +40 -40
- package/src/stories/LiveTranscription.stories.tsx +153 -0
- package/src/stories/TranscriptionStory.tsx +101 -0
- package/src/stories/common.ts +233 -0
- package/src/testing/testing.ts +49 -56
- package/src/transcriber/index.ts +1 -1
- package/src/transcriber/media-stream-recorder.ts +3 -3
- package/src/transcriber/transcriber.browser.test.ts +4 -5
- package/src/transcriber/transcriber.test.ts +104 -0
- package/src/transcriber/transcriber.ts +105 -60
- package/src/transcriber/transcription-manager.ts +33 -22
- package/src/translations.ts +10 -7
- package/src/types/TranscriptOperation.ts +103 -0
- package/src/types/TranscriptionCapabilities.ts +39 -0
- package/src/types/index.ts +2 -3
- package/src/util/index.ts +1 -0
- package/src/util/render-byline.ts +33 -0
- package/dist/lib/browser/TranscriptContainer-2GSL2XB5.mjs +0 -11
- package/dist/lib/browser/blueprint-definition-UAAJYVLZ.mjs +0 -150
- package/dist/lib/browser/blueprint-definition-UAAJYVLZ.mjs.map +0 -7
- package/dist/lib/browser/chunk-3MKZ2MNQ.mjs +0 -16
- package/dist/lib/browser/chunk-3MKZ2MNQ.mjs.map +0 -7
- package/dist/lib/browser/chunk-535OJKFO.mjs +0 -8
- package/dist/lib/browser/chunk-535OJKFO.mjs.map +0 -7
- package/dist/lib/browser/chunk-7DR6HZEF.mjs +0 -732
- package/dist/lib/browser/chunk-7DR6HZEF.mjs.map +0 -7
- package/dist/lib/browser/chunk-VBUIO677.mjs.map +0 -7
- package/dist/lib/browser/chunk-W7WKZTM4.mjs +0 -63
- package/dist/lib/browser/chunk-W7WKZTM4.mjs.map +0 -7
- package/dist/lib/browser/chunk-WH36ENNE.mjs.map +0 -7
- package/dist/lib/browser/index.mjs +0 -130
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/intent-resolver-ZTKTEAQX.mjs +0 -25
- package/dist/lib/browser/intent-resolver-ZTKTEAQX.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/react-surface-KA32A72I.mjs +0 -34
- package/dist/lib/browser/react-surface-KA32A72I.mjs.map +0 -7
- package/dist/lib/browser/transcriber-LWOLYQHC.mjs +0 -56
- package/dist/lib/browser/transcriber-LWOLYQHC.mjs.map +0 -7
- package/dist/lib/browser/types/index.mjs +0 -12
- package/dist/lib/node-esm/TranscriptContainer-GRLDCESB.mjs +0 -12
- package/dist/lib/node-esm/blueprint-definition-Z3LTZ3ID.mjs +0 -151
- package/dist/lib/node-esm/blueprint-definition-Z3LTZ3ID.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-K4AZOB5Y.mjs +0 -733
- package/dist/lib/node-esm/chunk-K4AZOB5Y.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-OLMSTF3M.mjs +0 -64
- package/dist/lib/node-esm/chunk-OLMSTF3M.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-Q6WD7L2J.mjs +0 -10
- package/dist/lib/node-esm/chunk-Q6WD7L2J.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-SWUVPFKR.mjs +0 -17
- package/dist/lib/node-esm/chunk-SWUVPFKR.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YFN4FJFK.mjs +0 -467
- package/dist/lib/node-esm/chunk-YFN4FJFK.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-YVNQN2J6.mjs +0 -30
- package/dist/lib/node-esm/chunk-YVNQN2J6.mjs.map +0 -7
- package/dist/lib/node-esm/index.mjs +0 -131
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/intent-resolver-55WH2GY6.mjs +0 -26
- package/dist/lib/node-esm/intent-resolver-55WH2GY6.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/react-surface-GU7LW2JO.mjs +0 -35
- package/dist/lib/node-esm/react-surface-GU7LW2JO.mjs.map +0 -7
- package/dist/lib/node-esm/transcriber-UGB7ECX6.mjs.map +0 -7
- package/dist/lib/node-esm/types/index.mjs +0 -13
- package/dist/types/src/capabilities/capabilities.d.ts +0 -17
- package/dist/types/src/capabilities/capabilities.d.ts.map +0 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +0 -4
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +0 -1
- package/dist/types/src/components/Transcript/Transcript.d.ts +0 -20
- package/dist/types/src/components/Transcript/Transcript.d.ts.map +0 -1
- package/dist/types/src/components/Transcript/Transcript.stories.d.ts +0 -39
- package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +0 -1
- package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +0 -28
- package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +0 -1
- package/dist/types/src/components/Transcript/index.d.ts +0 -2
- package/dist/types/src/components/Transcript/index.d.ts.map +0 -1
- package/dist/types/src/components/Transcript/transcript-extension.d.ts +0 -15
- package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +0 -1
- package/dist/types/src/components/TranscriptContainer.d.ts +0 -9
- package/dist/types/src/components/TranscriptContainer.d.ts.map +0 -1
- package/dist/types/src/components/stories/FileTranscription.stories.d.ts +0 -18
- package/dist/types/src/components/stories/FileTranscription.stories.d.ts.map +0 -1
- package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts.map +0 -1
- package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts.map +0 -1
- package/dist/types/src/components/stories/TranscriptionStory.d.ts +0 -12
- package/dist/types/src/components/stories/TranscriptionStory.d.ts.map +0 -1
- package/dist/types/src/components/stories/useIsSpeaking.d.ts +0 -3
- package/dist/types/src/components/stories/useIsSpeaking.d.ts.map +0 -1
- package/dist/types/src/functions/index.d.ts +0 -3
- package/dist/types/src/functions/index.d.ts.map +0 -1
- package/dist/types/src/functions/open.d.ts +0 -7
- package/dist/types/src/functions/open.d.ts.map +0 -1
- package/dist/types/src/functions/summarize.d.ts +0 -11
- package/dist/types/src/functions/summarize.d.ts.map +0 -1
- package/dist/types/src/hooks/useQueueModelAdapter.d.ts +0 -8
- package/dist/types/src/hooks/useQueueModelAdapter.d.ts.map +0 -1
- package/dist/types/src/segments-normalization/index.d.ts.map +0 -1
- package/dist/types/src/segments-normalization/message-normalizer.d.ts.map +0 -1
- package/dist/types/src/segments-normalization/normalization.d.ts +0 -476
- package/dist/types/src/segments-normalization/normalization.d.ts.map +0 -1
- package/dist/types/src/segments-normalization/normalization.test.d.ts.map +0 -1
- package/dist/types/src/segments-normalization/utils.d.ts +0 -3
- package/dist/types/src/segments-normalization/utils.d.ts.map +0 -1
- package/dist/types/src/types/Transcript.d.ts +0 -30
- package/dist/types/src/types/Transcript.d.ts.map +0 -1
- package/dist/types/src/types/TranscriptAction.d.ts +0 -23
- package/dist/types/src/types/TranscriptAction.d.ts.map +0 -1
- package/dist/types/src/types/types.d.ts +0 -5
- package/dist/types/src/types/types.d.ts.map +0 -1
- package/src/capabilities/capabilities.ts +0 -33
- package/src/capabilities/intent-resolver.ts +0 -18
- package/src/components/Transcript/Transcript.stories.tsx +0 -245
- package/src/components/Transcript/Transcript.tsx +0 -93
- package/src/components/Transcript/deprecated/OldTranscript.tsx +0 -260
- package/src/components/TranscriptContainer.tsx +0 -36
- package/src/components/stories/FileTranscription.stories.tsx +0 -256
- package/src/components/stories/MicrophoneTranscription.stories.tsx +0 -285
- package/src/components/stories/TranscriptionStory.tsx +0 -45
- package/src/components/stories/useIsSpeaking.tsx +0 -40
- package/src/functions/index.ts +0 -6
- package/src/functions/open.ts +0 -39
- package/src/functions/summarize.ts +0 -103
- package/src/hooks/useQueueModelAdapter.ts +0 -66
- package/src/segments-normalization/normalization.ts +0 -115
- package/src/types/Transcript.ts +0 -44
- package/src/types/TranscriptAction.ts +0 -24
- package/src/types/types.ts +0 -9
- package/dist/lib/{browser/types → neutral/blueprints}/index.mjs.map +0 -0
- package/dist/lib/{browser/TranscriptContainer-2GSL2XB5.mjs.map → neutral/chunk-J5LGTIGS.mjs.map} +0 -0
- package/dist/lib/{node-esm/types → neutral/hooks}/index.mjs.map +0 -0
- package/dist/lib/{node-esm/TranscriptContainer-GRLDCESB.mjs.map → neutral/index.mjs.map} +0 -0
- package/dist/types/src/{segments-normalization → normalization}/normalization.test.d.ts +0 -0
- package/src/{segments-normalization → normalization}/index.ts +1 -1
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// Parser for the human-authored conversation fixture (see `conversation.txt`).
|
|
6
|
+
// Captures both the seed entities (Persons, Organizations, …) and the speaker-tagged
|
|
7
|
+
// dialogue used by `stream-simulator.ts` to feed the enrichment pipeline.
|
|
8
|
+
|
|
9
|
+
export type ConversationEntity = {
|
|
10
|
+
/** Type name as written in the fixture, e.g. `Person`, `Organization`. */
|
|
11
|
+
kind: string;
|
|
12
|
+
/** Free-form field values; consumers map these to the relevant ECHO schema. */
|
|
13
|
+
fields: Record<string, string>;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type ConversationUtterance = {
|
|
17
|
+
/** Speaker label as written in the fixture (e.g. `A`, `B`, `Rich`). */
|
|
18
|
+
speaker: string;
|
|
19
|
+
/** Raw utterance text. */
|
|
20
|
+
text: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type ParsedConversation = {
|
|
24
|
+
entities: ConversationEntity[];
|
|
25
|
+
utterances: ConversationUtterance[];
|
|
26
|
+
/** Distinct speaker labels in first-seen order. */
|
|
27
|
+
speakers: string[];
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Parse the on-disk conversation format into structured data.
|
|
32
|
+
*
|
|
33
|
+
* Tolerates leading whitespace inside blocks and ignores blank / `#` comment lines.
|
|
34
|
+
* Throws if the input doesn't contain a `Conversation:` block — `Entities:` is optional.
|
|
35
|
+
*/
|
|
36
|
+
export const parseConversation = (input: string): ParsedConversation => {
|
|
37
|
+
const lines = input.split('\n').map((line) => line.replace(/\s+$/, ''));
|
|
38
|
+
|
|
39
|
+
const entities: ConversationEntity[] = [];
|
|
40
|
+
const utterances: ConversationUtterance[] = [];
|
|
41
|
+
const speakerOrder = new Set<string>();
|
|
42
|
+
|
|
43
|
+
type Section = 'none' | 'entities' | 'conversation';
|
|
44
|
+
let section: Section = 'none';
|
|
45
|
+
let currentEntity: ConversationEntity | undefined;
|
|
46
|
+
|
|
47
|
+
for (const raw of lines) {
|
|
48
|
+
const line = raw.trim();
|
|
49
|
+
if (line.length === 0 || line.startsWith('#')) {
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Section headers (must be left-aligned to switch sections).
|
|
54
|
+
if (raw.startsWith('Entities:') || raw.startsWith('Entitites:')) {
|
|
55
|
+
// tolerate the typo present in earlier fixtures
|
|
56
|
+
section = 'entities';
|
|
57
|
+
currentEntity = undefined;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (raw.startsWith('Conversation:')) {
|
|
61
|
+
section = 'conversation';
|
|
62
|
+
currentEntity = undefined;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (section === 'entities') {
|
|
67
|
+
// `<TypeName>:` starts a new entity; nested `<field>: <value>` lines fill it.
|
|
68
|
+
const typeMatch = line.match(/^([A-Za-z][A-Za-z0-9_-]*):$/);
|
|
69
|
+
if (typeMatch) {
|
|
70
|
+
currentEntity = { kind: typeMatch[1], fields: {} };
|
|
71
|
+
entities.push(currentEntity);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const fieldMatch = line.match(/^([A-Za-z][A-Za-z0-9_-]*):\s*(.+)$/);
|
|
75
|
+
if (fieldMatch && currentEntity) {
|
|
76
|
+
currentEntity.fields[fieldMatch[1]] = fieldMatch[2];
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// Silently skip unrecognised lines so authors can add free-form annotations.
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (section === 'conversation') {
|
|
84
|
+
const utteranceMatch = line.match(/^([^:]+):\s*(.+)$/);
|
|
85
|
+
if (utteranceMatch) {
|
|
86
|
+
const speaker = utteranceMatch[1].trim();
|
|
87
|
+
const text = utteranceMatch[2].trim();
|
|
88
|
+
if (text.length > 0) {
|
|
89
|
+
utterances.push({ speaker, text });
|
|
90
|
+
speakerOrder.add(speaker);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (utterances.length === 0) {
|
|
97
|
+
throw new Error('parseConversation: no utterances found');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return { entities, utterances, speakers: Array.from(speakerOrder) };
|
|
101
|
+
};
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
// Turns a parsed conversation into a chronologically-ordered sequence of Whisper-shaped
|
|
6
|
+
// transcript batches, one per (speaker, utterance) pair. Each batch carries a virtual
|
|
7
|
+
// timestamp (ms since the conversation start) and the speaker label so consumers can fan
|
|
8
|
+
// out per-stream — analogous to two microphones being transcribed in parallel.
|
|
9
|
+
//
|
|
10
|
+
// The simulator does NOT do any wall-clock waiting. Tests drive virtual time via
|
|
11
|
+
// `vi.useFakeTimers()` or step through the batches directly; production code wouldn't use
|
|
12
|
+
// this module at all.
|
|
13
|
+
|
|
14
|
+
import { type ContentBlock } from '@dxos/types';
|
|
15
|
+
|
|
16
|
+
import type { ConversationUtterance, ParsedConversation } from './parser';
|
|
17
|
+
|
|
18
|
+
export type StreamSimulatorOptions = {
|
|
19
|
+
/**
|
|
20
|
+
* Average speaking rate, words per second. Used to assign a virtual duration to each
|
|
21
|
+
* utterance so consecutive utterances land at realistic offsets.
|
|
22
|
+
* @default 2.5 (≈150 wpm — typical conversational pace)
|
|
23
|
+
*/
|
|
24
|
+
wordsPerSecond?: number;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Gap between consecutive utterances in seconds. Models a brief pause for turn-taking
|
|
28
|
+
* even when speakers don't actually overlap.
|
|
29
|
+
* @default 0.5
|
|
30
|
+
*/
|
|
31
|
+
gapSeconds?: number;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Whisper batches typically arrive in chunks of N seconds rather than per-utterance.
|
|
35
|
+
* When set, utterances shorter than `batchSeconds` are merged into the same batch as
|
|
36
|
+
* the following utterance from the same speaker. `0` disables merging — every utterance
|
|
37
|
+
* is its own batch.
|
|
38
|
+
* @default 0
|
|
39
|
+
*/
|
|
40
|
+
batchSeconds?: number;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
export type SimulatedBatch = {
|
|
44
|
+
/** Speaker label from the fixture (`A`, `B`, …). Maps to a virtual `identityDid`. */
|
|
45
|
+
speaker: string;
|
|
46
|
+
/** ms offset from the conversation start when this batch is delivered. */
|
|
47
|
+
offsetMs: number;
|
|
48
|
+
/** Whisper-shaped transcript blocks (raw text, no enrichment). */
|
|
49
|
+
blocks: ContentBlock.Transcript[];
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Build the chronological batch schedule for a parsed conversation. The result is a
|
|
54
|
+
* pure data structure — consumers iterate and drive virtual time themselves.
|
|
55
|
+
*/
|
|
56
|
+
export const simulateStream = (
|
|
57
|
+
conversation: ParsedConversation,
|
|
58
|
+
options: StreamSimulatorOptions = {},
|
|
59
|
+
): SimulatedBatch[] => {
|
|
60
|
+
const wordsPerSecond = options.wordsPerSecond ?? 2.5;
|
|
61
|
+
const gapSeconds = options.gapSeconds ?? 0.5;
|
|
62
|
+
const batchSeconds = options.batchSeconds ?? 0;
|
|
63
|
+
|
|
64
|
+
// Guard against divide-by-zero / NaN / negative inputs — `wordsPerSecond` divides into a
|
|
65
|
+
// duration below, and the other knobs feed into offsets that must be finite.
|
|
66
|
+
if (!Number.isFinite(wordsPerSecond) || wordsPerSecond <= 0) {
|
|
67
|
+
throw new Error(`simulateStream: wordsPerSecond must be a finite number > 0 (got ${wordsPerSecond}).`);
|
|
68
|
+
}
|
|
69
|
+
if (!Number.isFinite(gapSeconds) || gapSeconds < 0) {
|
|
70
|
+
throw new Error(`simulateStream: gapSeconds must be a finite number >= 0 (got ${gapSeconds}).`);
|
|
71
|
+
}
|
|
72
|
+
if (!Number.isFinite(batchSeconds) || batchSeconds < 0) {
|
|
73
|
+
throw new Error(`simulateStream: batchSeconds must be a finite number >= 0 (got ${batchSeconds}).`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const conversationStart = Date.UTC(2024, 0, 1, 12, 0, 0); // deterministic, ignored by callers
|
|
77
|
+
let cursorMs = 0;
|
|
78
|
+
const batches: SimulatedBatch[] = [];
|
|
79
|
+
|
|
80
|
+
// Optionally merge same-speaker consecutive utterances until they reach `batchSeconds`.
|
|
81
|
+
const grouped: { speaker: string; utterances: ConversationUtterance[] }[] = [];
|
|
82
|
+
if (batchSeconds === 0) {
|
|
83
|
+
for (const u of conversation.utterances) {
|
|
84
|
+
grouped.push({ speaker: u.speaker, utterances: [u] });
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
let pending: { speaker: string; utterances: ConversationUtterance[]; words: number } | undefined;
|
|
88
|
+
for (const u of conversation.utterances) {
|
|
89
|
+
const words = utteranceWordCount(u.text);
|
|
90
|
+
if (pending && pending.speaker === u.speaker && pending.words / wordsPerSecond < batchSeconds) {
|
|
91
|
+
pending.utterances.push(u);
|
|
92
|
+
pending.words += words;
|
|
93
|
+
} else {
|
|
94
|
+
if (pending) {
|
|
95
|
+
grouped.push({ speaker: pending.speaker, utterances: pending.utterances });
|
|
96
|
+
}
|
|
97
|
+
pending = { speaker: u.speaker, utterances: [u], words };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (pending) {
|
|
101
|
+
grouped.push({ speaker: pending.speaker, utterances: pending.utterances });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
for (const group of grouped) {
|
|
106
|
+
const startMs = cursorMs;
|
|
107
|
+
const blocks: ContentBlock.Transcript[] = [];
|
|
108
|
+
let segmentCursorMs = cursorMs;
|
|
109
|
+
for (const u of group.utterances) {
|
|
110
|
+
const durationMs = Math.max(500, (utteranceWordCount(u.text) / wordsPerSecond) * 1_000);
|
|
111
|
+
blocks.push({
|
|
112
|
+
_tag: 'transcript',
|
|
113
|
+
started: new Date(conversationStart + segmentCursorMs).toISOString(),
|
|
114
|
+
text: u.text,
|
|
115
|
+
});
|
|
116
|
+
segmentCursorMs += durationMs;
|
|
117
|
+
}
|
|
118
|
+
batches.push({ speaker: group.speaker, offsetMs: startMs, blocks });
|
|
119
|
+
cursorMs = segmentCursorMs + gapSeconds * 1_000;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return batches;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
const utteranceWordCount = (text: string): number => text.trim().split(/\s+/).filter(Boolean).length;
|
package/src/hooks/index.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
export * from './useAudioFile';
|
|
6
6
|
export * from './useAudioTrack';
|
|
7
|
-
export * from './
|
|
7
|
+
export * from './useFeedModelAdapter';
|
|
8
8
|
export * from './useTranscriber';
|
|
9
|
+
export * from './useTranscriptionRecording';
|
|
9
10
|
export * from './useVoiceInput';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useEffect, useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import type { Obj } from '@dxos/echo';
|
|
8
|
+
|
|
9
|
+
import { type ChunkRenderer, SerializationModel } from '../model';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Feeds an array of objects (typically from `useQuery(db, Query.from(feed))`) into a
|
|
13
|
+
* `SerializationModel`, appending each new tail item as the array grows.
|
|
14
|
+
*
|
|
15
|
+
* @param renderer - chunk renderer.
|
|
16
|
+
* @param objects - current snapshot of feed items.
|
|
17
|
+
* @param initialChunks - chunks to seed the model with on first render.
|
|
18
|
+
*/
|
|
19
|
+
export const useFeedModelAdapter = <T extends Obj.Unknown>(
|
|
20
|
+
renderer: ChunkRenderer<T>,
|
|
21
|
+
objects: readonly T[],
|
|
22
|
+
initialChunks: T[] = [],
|
|
23
|
+
): SerializationModel<T> => {
|
|
24
|
+
const model = useMemo(() => new SerializationModel<T>(renderer, initialChunks), [renderer]);
|
|
25
|
+
|
|
26
|
+
// Seed the model with the current snapshot on first render and whenever the
|
|
27
|
+
// identity of `objects` changes (e.g. feed swapped).
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
for (const chunk of objects) {
|
|
30
|
+
model.appendChunk(chunk);
|
|
31
|
+
}
|
|
32
|
+
}, [model, objects]);
|
|
33
|
+
|
|
34
|
+
// Append new tail items as the array grows.
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (model.chunks.length === objects.length) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const chunk = objects.at(-1);
|
|
40
|
+
if (chunk) {
|
|
41
|
+
model.appendChunk(chunk);
|
|
42
|
+
}
|
|
43
|
+
}, [model, objects.length]);
|
|
44
|
+
|
|
45
|
+
return model;
|
|
46
|
+
};
|
|
@@ -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,6 +18,7 @@ export const useTranscriber = ({
|
|
|
17
18
|
recorderConfig,
|
|
18
19
|
transcriberConfig,
|
|
19
20
|
onSegments,
|
|
21
|
+
transcribe,
|
|
20
22
|
}: Partial<TranscriptionCapabilities.GetTranscriberProps>) => {
|
|
21
23
|
const [getTranscriber] = useCapabilities(TranscriptionCapabilities.Transcriber);
|
|
22
24
|
|
|
@@ -26,8 +28,14 @@ export const useTranscriber = ({
|
|
|
26
28
|
return undefined;
|
|
27
29
|
}
|
|
28
30
|
|
|
29
|
-
return getTranscriber({
|
|
30
|
-
|
|
31
|
+
return getTranscriber({
|
|
32
|
+
audioStreamTrack,
|
|
33
|
+
recorderConfig,
|
|
34
|
+
transcriberConfig,
|
|
35
|
+
onSegments,
|
|
36
|
+
transcribe,
|
|
37
|
+
});
|
|
38
|
+
}, [getTranscriber, 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 { runAndForwardErrors } 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), 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
|
+
};
|
|
@@ -9,8 +9,7 @@ import { Context } from '@dxos/context';
|
|
|
9
9
|
import { log } from '@dxos/log';
|
|
10
10
|
import { useSoundEffect } from '@dxos/react-ui-sfx';
|
|
11
11
|
|
|
12
|
-
import { type
|
|
13
|
-
|
|
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<
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
export * from './
|
|
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,11 +2,11 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type Plugin } from '@dxos/app-framework';
|
|
6
6
|
import { trim } from '@dxos/util';
|
|
7
7
|
|
|
8
|
-
export const meta:
|
|
9
|
-
id: 'dxos.
|
|
8
|
+
export const meta: Plugin.Meta = {
|
|
9
|
+
id: 'org.dxos.plugin.transcription',
|
|
10
10
|
name: 'Transcription',
|
|
11
11
|
description: trim`
|
|
12
12
|
Real-time voice-to-text transcription service for capturing spoken content.
|
package/src/model/model.test.ts
CHANGED
|
@@ -7,12 +7,12 @@ import { describe, test } from 'vitest';
|
|
|
7
7
|
|
|
8
8
|
import { Obj } from '@dxos/echo';
|
|
9
9
|
import type { ObjectId } from '@dxos/keys';
|
|
10
|
-
import {
|
|
10
|
+
import { Message } from '@dxos/types';
|
|
11
11
|
|
|
12
12
|
import { type ChunkRenderer, DocumentAdapter, SerializationModel } from './model';
|
|
13
13
|
|
|
14
|
-
const blockToMarkdown: ChunkRenderer<
|
|
15
|
-
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<
|
|
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(
|
|
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
|
-
|
|
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<
|
|
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(
|
|
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(
|
|
92
|
+
const message = Obj.make(Message.Message, {
|
|
91
93
|
created: createDate(),
|
|
92
94
|
sender: { name: 'Bob' },
|
|
93
95
|
blocks: [
|
|
@@ -106,7 +108,7 @@ 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<
|
|
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
|
|
|
@@ -114,7 +116,7 @@ describe('SerializationModel', () => {
|
|
|
114
116
|
|
|
115
117
|
// Append message.
|
|
116
118
|
{
|
|
117
|
-
const message = Obj.make(
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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!' }],
|
package/src/model/model.ts
CHANGED
|
@@ -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[] = [],
|