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