@dxos/plugin-transcription 0.9.1-main.c7dcc2e112 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PLUGIN.mdl +5 -5
- package/dist/lib/neutral/{TranscriptionArticle-S56VVOSF.mjs → TranscriptionArticle-FEWCWG4A.mjs} +3 -6
- package/dist/lib/neutral/TranscriptionArticle-FEWCWG4A.mjs.map +7 -0
- package/dist/lib/neutral/TranscriptionPlugin.mjs +25 -4
- package/dist/lib/neutral/TranscriptionPlugin.mjs.map +3 -3
- package/dist/lib/neutral/TranscriptionPlugin.node.mjs +3 -3
- package/dist/lib/neutral/TranscriptionPlugin.node.mjs.map +3 -3
- package/dist/lib/neutral/app-graph-builder-GQRMI22E.mjs +48 -0
- package/dist/lib/neutral/app-graph-builder-GQRMI22E.mjs.map +7 -0
- package/dist/lib/neutral/capabilities/index.mjs +17 -5
- package/dist/lib/neutral/capabilities/index.mjs.map +3 -3
- package/dist/lib/neutral/{chunk-XZVDAYM6.mjs → chunk-5BVHY75B.mjs} +2 -2
- package/dist/lib/neutral/{chunk-XZVDAYM6.mjs.map → chunk-5BVHY75B.mjs.map} +1 -1
- package/dist/lib/neutral/chunk-HNXSU7HJ.mjs +8 -0
- package/dist/lib/neutral/chunk-KOXLGGSL.mjs +30 -0
- package/dist/lib/neutral/chunk-KOXLGGSL.mjs.map +7 -0
- package/dist/lib/neutral/{chunk-2URVUJT4.mjs → chunk-MDV7NBFJ.mjs} +31 -8
- package/dist/lib/neutral/chunk-MDV7NBFJ.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +114 -258
- package/dist/lib/neutral/components/index.mjs.map +4 -4
- package/dist/lib/neutral/containers/index.mjs +1 -1
- package/dist/lib/neutral/{create-7NGOP7JP.mjs → create-HNHGCKZ4.mjs} +2 -2
- package/dist/lib/neutral/{enrich-message-F2AOM53F.mjs → enrich-message-DSJU4TXC.mjs} +2 -2
- package/dist/lib/neutral/entity-lookup-PCDW7NC4.mjs +25 -0
- package/dist/lib/neutral/entity-lookup-PCDW7NC4.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +93 -15
- package/dist/lib/neutral/hooks/index.mjs.map +4 -4
- package/dist/lib/neutral/index.mjs +6 -32
- package/dist/lib/neutral/markdown-extension-CCDXXY7E.mjs +16 -0
- package/dist/lib/neutral/markdown-extension-CCDXXY7E.mjs.map +7 -0
- package/dist/lib/neutral/meta.json +1 -1
- package/dist/lib/neutral/meta.mjs +1 -1
- package/dist/lib/neutral/{open-42H72C4G.mjs → open-SNMZXXYO.mjs} +4 -6
- package/dist/lib/neutral/open-SNMZXXYO.mjs.map +7 -0
- package/dist/lib/neutral/operations/index.mjs +1 -1
- package/dist/lib/neutral/pipeline-status-XMWMAUJY.mjs +17 -0
- package/dist/lib/neutral/pipeline-status-XMWMAUJY.mjs.map +7 -0
- package/dist/lib/neutral/plugin.mjs +2 -2
- package/dist/lib/neutral/recording-session-IADO7ATU.mjs +15 -0
- package/dist/lib/neutral/recording-session-IADO7ATU.mjs.map +7 -0
- package/dist/lib/neutral/{settings-DUS32HOM.mjs → settings-7KE4MABW.mjs} +3 -2
- package/dist/lib/neutral/{settings-DUS32HOM.mjs.map → settings-7KE4MABW.mjs.map} +3 -3
- package/dist/lib/neutral/skill-definition-DXNK324V.mjs +15 -0
- package/dist/lib/neutral/skill-definition-DXNK324V.mjs.map +7 -0
- package/dist/lib/neutral/skills/index.mjs +8 -0
- package/dist/lib/neutral/{summarize-45WVUPED.mjs → summarize-LBUZTOTH.mjs} +4 -4
- package/dist/lib/neutral/summarize-LBUZTOTH.mjs.map +7 -0
- package/dist/lib/neutral/{text-content-XZ3HK4OT.mjs → text-content-NOWR642C.mjs} +2 -4
- package/dist/lib/neutral/text-content-NOWR642C.mjs.map +7 -0
- package/dist/lib/neutral/transcriber-6XZHUUHK.mjs +174 -0
- package/dist/lib/neutral/transcriber-6XZHUUHK.mjs.map +7 -0
- package/dist/lib/neutral/transcription-driver-DN6ELQXZ.mjs +207 -0
- package/dist/lib/neutral/transcription-driver-DN6ELQXZ.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +7 -0
- package/dist/lib/neutral/translations.mjs.map +2 -2
- package/dist/lib/neutral/types/index.mjs +1 -1
- package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/app-graph-builder.d.ts +5 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -0
- package/dist/types/src/capabilities/entity-lookup.d.ts +10 -0
- package/dist/types/src/capabilities/entity-lookup.d.ts.map +1 -0
- package/dist/types/src/capabilities/index.d.ts +7 -1
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/markdown-extension.d.ts +5 -0
- package/dist/types/src/capabilities/markdown-extension.d.ts.map +1 -0
- package/dist/types/src/capabilities/pipeline-status.d.ts +9 -0
- package/dist/types/src/capabilities/pipeline-status.d.ts.map +1 -0
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/recording-session.d.ts +5 -0
- package/dist/types/src/capabilities/recording-session.d.ts.map +1 -0
- package/dist/types/src/capabilities/settings.d.ts +1 -3
- package/dist/types/src/capabilities/settings.d.ts.map +1 -1
- package/dist/types/src/capabilities/skill-definition.d.ts +5 -0
- package/dist/types/src/capabilities/skill-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/text-content.d.ts +1 -4
- 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/capabilities/transcription-driver.d.ts +5 -0
- package/dist/types/src/capabilities/transcription-driver.d.ts.map +1 -0
- package/dist/types/src/components/Mic/Mic.d.ts +12 -0
- package/dist/types/src/components/Mic/Mic.d.ts.map +1 -0
- package/dist/types/src/components/{Oracle/Oracle.stories.d.ts → Mic/Mic.stories.d.ts} +9 -7
- package/dist/types/src/components/Mic/Mic.stories.d.ts.map +1 -0
- package/dist/types/src/components/Mic/index.d.ts +2 -0
- package/dist/types/src/components/Mic/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +1 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts.map +1 -1
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts +7 -0
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +0 -5
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTranscriptionRecording.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -3
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +4 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/normalization/message-normalizer.d.ts +2 -2
- package/dist/types/src/normalization/message-normalizer.d.ts.map +1 -1
- package/dist/types/src/normalization/normalization.d.ts +98 -733
- package/dist/types/src/normalization/normalization.d.ts.map +1 -1
- package/dist/types/src/operations/open.d.ts.map +1 -1
- package/dist/types/src/operations/summarize.d.ts.map +1 -1
- package/dist/types/src/skills/index.d.ts +2 -0
- package/dist/types/src/skills/index.d.ts.map +1 -0
- package/dist/types/src/skills/transcription-skill.d.ts +4 -0
- package/dist/types/src/skills/transcription-skill.d.ts.map +1 -0
- package/dist/types/src/stories/Keyword.stories.d.ts +51 -0
- package/dist/types/src/stories/Keyword.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Pipeline.stories.d.ts +60 -0
- package/dist/types/src/stories/Pipeline.stories.d.ts.map +1 -0
- package/dist/types/src/stories/Transcription.stories.d.ts +23 -0
- package/dist/types/src/stories/Transcription.stories.d.ts.map +1 -0
- package/dist/types/src/testing/decorators.d.ts +21 -0
- package/dist/types/src/testing/decorators.d.ts.map +1 -0
- package/dist/types/src/testing/index.d.ts +1 -0
- package/dist/types/src/testing/index.d.ts.map +1 -1
- package/dist/types/src/testing/testing.d.ts +3 -9
- package/dist/types/src/testing/testing.d.ts.map +1 -1
- package/dist/types/src/{transcriber/transcription-manager.d.ts → transcription-manager.d.ts} +6 -5
- package/dist/types/src/transcription-manager.d.ts.map +1 -0
- package/dist/types/src/translations.d.ts +7 -0
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types/Settings.d.ts +6 -0
- package/dist/types/src/types/Settings.d.ts.map +1 -1
- package/dist/types/src/types/TranscriptOperation.d.ts +114 -1971
- package/dist/types/src/types/TranscriptOperation.d.ts.map +1 -1
- package/dist/types/src/types/TranscriptionCapabilities.d.ts +51 -13
- package/dist/types/src/types/TranscriptionCapabilities.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +0 -2
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -1
- package/package.json +68 -69
- package/src/TranscriptionPlugin.node.ts +2 -2
- package/src/TranscriptionPlugin.test.ts +1 -1
- package/src/TranscriptionPlugin.tsx +31 -2
- package/src/capabilities/app-graph-builder.tsx +49 -0
- package/src/capabilities/entity-lookup.ts +32 -0
- package/src/capabilities/index.ts +7 -1
- package/src/capabilities/markdown-extension.ts +17 -0
- package/src/capabilities/pipeline-status.ts +23 -0
- package/src/capabilities/recording-session.ts +17 -0
- package/src/capabilities/settings.ts +1 -0
- package/src/capabilities/skill-definition.ts +15 -0
- package/src/capabilities/text-content.ts +1 -2
- package/src/capabilities/transcriber.ts +5 -48
- package/src/capabilities/transcription-driver.tsx +263 -0
- package/src/components/Mic/Mic.stories.tsx +66 -0
- package/src/components/Mic/Mic.tsx +136 -0
- package/src/components/Mic/index.ts +5 -0
- package/src/components/index.ts +1 -2
- package/src/containers/TranscriptionArticle/TranscriptionArticle.stories.tsx +4 -0
- package/src/containers/TranscriptionArticle/TranscriptionArticle.tsx +4 -5
- package/src/hooks/index.ts +0 -5
- package/src/hooks/useTranscriptionRecording.ts +4 -8
- package/src/index.ts +1 -5
- package/src/normalization/message-normalizer.ts +3 -3
- package/src/normalization/normalization.ts +3 -0
- package/src/operations/open.ts +2 -2
- package/src/operations/summarize.ts +2 -2
- package/src/skills/index.ts +5 -0
- package/src/skills/transcription-skill.ts +29 -0
- package/src/stories/Keyword.stories.tsx +98 -0
- package/src/stories/Pipeline.stories.tsx +361 -0
- package/src/stories/Transcription.stories.tsx +178 -0
- package/src/testing/decorators.ts +78 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/testing.ts +13 -48
- package/src/{transcriber/transcription-manager.ts → transcription-manager.ts} +13 -12
- package/src/translations.ts +8 -0
- package/src/types/Settings.ts +38 -0
- package/src/types/TranscriptOperation.ts +6 -4
- package/src/types/TranscriptionCapabilities.ts +57 -21
- package/src/util/index.ts +0 -2
- package/dist/lib/neutral/TranscriptionArticle-S56VVOSF.mjs.map +0 -7
- package/dist/lib/neutral/blueprint-definition-DA4QFRYJ.mjs +0 -15
- package/dist/lib/neutral/blueprint-definition-DA4QFRYJ.mjs.map +0 -7
- package/dist/lib/neutral/blueprints/index.mjs +0 -8
- package/dist/lib/neutral/chunk-2URVUJT4.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J4ONEYPJ.mjs +0 -8
- package/dist/lib/neutral/chunk-MLRJWAQH.mjs +0 -179
- package/dist/lib/neutral/chunk-MLRJWAQH.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XMHH34NI.mjs +0 -318
- package/dist/lib/neutral/chunk-XMHH34NI.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XOXHWMXR.mjs +0 -35
- package/dist/lib/neutral/chunk-XOXHWMXR.mjs.map +0 -7
- package/dist/lib/neutral/chunk-XWC5BBOY.mjs +0 -435
- package/dist/lib/neutral/chunk-XWC5BBOY.mjs.map +0 -7
- package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs +0 -30
- package/dist/lib/neutral/chunk-ZR4BH4QQ.mjs.map +0 -7
- package/dist/lib/neutral/open-42H72C4G.mjs.map +0 -7
- package/dist/lib/neutral/summarize-45WVUPED.mjs.map +0 -7
- package/dist/lib/neutral/text-content-XZ3HK4OT.mjs.map +0 -7
- package/dist/lib/neutral/transcriber-KYV6NWI5.mjs +0 -59
- package/dist/lib/neutral/transcriber-KYV6NWI5.mjs.map +0 -7
- package/dist/types/src/blueprints/index.d.ts +0 -2
- package/dist/types/src/blueprints/index.d.ts.map +0 -1
- package/dist/types/src/blueprints/transcription-blueprint.d.ts +0 -4
- package/dist/types/src/blueprints/transcription-blueprint.d.ts.map +0 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts +0 -6
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +0 -1
- package/dist/types/src/components/Oracle/Oracle.d.ts +0 -24
- package/dist/types/src/components/Oracle/Oracle.d.ts.map +0 -1
- package/dist/types/src/components/Oracle/Oracle.stories.d.ts.map +0 -1
- package/dist/types/src/components/Oracle/index.d.ts +0 -2
- package/dist/types/src/components/Oracle/index.d.ts.map +0 -1
- package/dist/types/src/components/Transcription/Transcription.d.ts +0 -11
- package/dist/types/src/components/Transcription/Transcription.d.ts.map +0 -1
- package/dist/types/src/components/Transcription/Transcription.stories.d.ts +0 -37
- package/dist/types/src/components/Transcription/Transcription.stories.d.ts.map +0 -1
- package/dist/types/src/components/Transcription/index.d.ts +0 -2
- package/dist/types/src/components/Transcription/index.d.ts.map +0 -1
- package/dist/types/src/components/Transcription/transcription-extension.d.ts +0 -15
- package/dist/types/src/components/Transcription/transcription-extension.d.ts.map +0 -1
- package/dist/types/src/enrichment/conversation.test.d.ts +0 -2
- package/dist/types/src/enrichment/conversation.test.d.ts.map +0 -1
- package/dist/types/src/enrichment/operations.d.ts +0 -200
- package/dist/types/src/enrichment/operations.d.ts.map +0 -1
- package/dist/types/src/enrichment/parser.d.ts +0 -26
- package/dist/types/src/enrichment/parser.d.ts.map +0 -1
- package/dist/types/src/enrichment/stream-simulator.d.ts +0 -38
- package/dist/types/src/enrichment/stream-simulator.d.ts.map +0 -1
- package/dist/types/src/hooks/useAudioFile.d.ts +0 -7
- package/dist/types/src/hooks/useAudioFile.d.ts.map +0 -1
- package/dist/types/src/hooks/useAudioTrack.d.ts +0 -5
- package/dist/types/src/hooks/useAudioTrack.d.ts.map +0 -1
- package/dist/types/src/hooks/useFeedModelAdapter.d.ts +0 -12
- package/dist/types/src/hooks/useFeedModelAdapter.d.ts.map +0 -1
- package/dist/types/src/hooks/useTranscriber.d.ts +0 -7
- package/dist/types/src/hooks/useTranscriber.d.ts.map +0 -1
- package/dist/types/src/hooks/useVoiceInput.d.ts +0 -11
- package/dist/types/src/hooks/useVoiceInput.d.ts.map +0 -1
- package/dist/types/src/model/index.d.ts +0 -2
- package/dist/types/src/model/index.d.ts.map +0 -1
- package/dist/types/src/model/model.d.ts +0 -68
- package/dist/types/src/model/model.d.ts.map +0 -1
- package/dist/types/src/model/model.test.d.ts +0 -2
- package/dist/types/src/model/model.test.d.ts.map +0 -1
- package/dist/types/src/stories/FileTranscription.stories.d.ts +0 -20
- package/dist/types/src/stories/FileTranscription.stories.d.ts.map +0 -1
- package/dist/types/src/stories/KeyWordRecognition.stories.d.ts +0 -14
- package/dist/types/src/stories/KeyWordRecognition.stories.d.ts.map +0 -1
- package/dist/types/src/stories/LiveTranscription.stories.d.ts +0 -19
- package/dist/types/src/stories/LiveTranscription.stories.d.ts.map +0 -1
- package/dist/types/src/stories/ProperNounExtraction.stories.d.ts +0 -13
- package/dist/types/src/stories/ProperNounExtraction.stories.d.ts.map +0 -1
- package/dist/types/src/stories/TranscriptionStory.d.ts +0 -21
- package/dist/types/src/stories/TranscriptionStory.d.ts.map +0 -1
- package/dist/types/src/stories/common.d.ts +0 -248
- package/dist/types/src/stories/common.d.ts.map +0 -1
- package/dist/types/src/transcriber/audio-recorder.d.ts +0 -47
- package/dist/types/src/transcriber/audio-recorder.d.ts.map +0 -1
- package/dist/types/src/transcriber/index.d.ts +0 -5
- package/dist/types/src/transcriber/index.d.ts.map +0 -1
- package/dist/types/src/transcriber/media-stream-recorder.d.ts +0 -30
- package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +0 -1
- package/dist/types/src/transcriber/transcriber.browser.test.d.ts +0 -2
- package/dist/types/src/transcriber/transcriber.browser.test.d.ts.map +0 -1
- package/dist/types/src/transcriber/transcriber.d.ts +0 -105
- package/dist/types/src/transcriber/transcriber.d.ts.map +0 -1
- package/dist/types/src/transcriber/transcriber.test.d.ts +0 -2
- package/dist/types/src/transcriber/transcriber.test.d.ts.map +0 -1
- package/dist/types/src/transcriber/transcription-manager.d.ts.map +0 -1
- package/dist/types/src/util/array.d.ts +0 -2
- package/dist/types/src/util/array.d.ts.map +0 -1
- package/dist/types/src/util/render-byline.d.ts +0 -4
- package/dist/types/src/util/render-byline.d.ts.map +0 -1
- package/src/blueprints/index.ts +0 -5
- package/src/blueprints/transcription-blueprint.ts +0 -29
- package/src/capabilities/blueprint-definition.ts +0 -19
- package/src/components/Oracle/Oracle.stories.tsx +0 -147
- package/src/components/Oracle/Oracle.tsx +0 -142
- package/src/components/Oracle/index.ts +0 -5
- package/src/components/Transcription/Transcription.stories.tsx +0 -213
- package/src/components/Transcription/Transcription.tsx +0 -55
- package/src/components/Transcription/index.ts +0 -5
- package/src/components/Transcription/transcription-extension.ts +0 -203
- package/src/enrichment/conversation.test.ts +0 -162
- package/src/enrichment/conversation.txt +0 -23
- package/src/enrichment/operations.ts +0 -271
- package/src/enrichment/parser.ts +0 -101
- package/src/enrichment/stream-simulator.ts +0 -125
- package/src/hooks/useAudioFile.ts +0 -88
- package/src/hooks/useAudioTrack.ts +0 -35
- package/src/hooks/useFeedModelAdapter.ts +0 -46
- package/src/hooks/useTranscriber.ts +0 -47
- package/src/hooks/useVoiceInput.ts +0 -66
- package/src/model/index.ts +0 -5
- package/src/model/model.test.ts +0 -175
- package/src/model/model.ts +0 -229
- package/src/stories/FileTranscription.stories.tsx +0 -143
- package/src/stories/KeyWordRecognition.stories.tsx +0 -132
- package/src/stories/LiveTranscription.stories.tsx +0 -99
- package/src/stories/ProperNounExtraction.stories.tsx +0 -99
- package/src/stories/TranscriptionStory.tsx +0 -101
- package/src/stories/common.ts +0 -234
- package/src/transcriber/audio-recorder.ts +0 -56
- package/src/transcriber/index.ts +0 -8
- package/src/transcriber/media-stream-recorder.ts +0 -120
- package/src/transcriber/transcriber.browser.test.ts +0 -230
- package/src/transcriber/transcriber.test.ts +0 -104
- package/src/transcriber/transcriber.ts +0 -303
- package/src/util/array.ts +0 -14
- package/src/util/render-byline.ts +0 -33
- /package/dist/lib/neutral/{chunk-J4ONEYPJ.mjs.map → chunk-HNXSU7HJ.mjs.map} +0 -0
- /package/dist/lib/neutral/{create-7NGOP7JP.mjs.map → create-HNHGCKZ4.mjs.map} +0 -0
- /package/dist/lib/neutral/{enrich-message-F2AOM53F.mjs.map → enrich-message-DSJU4TXC.mjs.map} +0 -0
- /package/dist/lib/neutral/{blueprints → skills}/index.mjs.map +0 -0
|
@@ -12,21 +12,45 @@ var Settings = Schema.mutable(Schema.Struct({
|
|
|
12
12
|
entityExtraction: Schema.optional(Schema.Boolean.annotations({
|
|
13
13
|
title: "Entity extraction",
|
|
14
14
|
description: "While transcribing, use the Assistant to detect and annotate mentions of known objects such as people or organizations."
|
|
15
|
-
})).pipe(Schema.withConstructorDefault(() => true))
|
|
15
|
+
})).pipe(Schema.withConstructorDefault(() => true)),
|
|
16
|
+
recordMode: Schema.optional(Schema.Literal("toggle", "hold").annotations({
|
|
17
|
+
title: "Record mode",
|
|
18
|
+
description: "Whether the mic toggles recording on each click, or records only while the control is held (push-to-talk)."
|
|
19
|
+
})).pipe(Schema.withConstructorDefault(() => "toggle")),
|
|
20
|
+
audioDeviceId: Schema.optional(Schema.String.annotations({
|
|
21
|
+
title: "Audio input device",
|
|
22
|
+
description: "Identifier of the microphone to capture from; empty uses the system default."
|
|
23
|
+
})),
|
|
24
|
+
transcribeAfterMs: Schema.optional(Schema.Number.annotations({
|
|
25
|
+
title: "Initial buffering (ms)",
|
|
26
|
+
description: "How long to accumulate audio before producing the first transcription."
|
|
27
|
+
})).pipe(Schema.withConstructorDefault(() => 4e3)),
|
|
28
|
+
streamMode: Schema.optional(Schema.Literal("batch", "word").annotations({
|
|
29
|
+
title: "Reveal mode",
|
|
30
|
+
description: "Whether transcribed text appears in batches or streams word-by-word."
|
|
31
|
+
})).pipe(Schema.withConstructorDefault(() => "word")),
|
|
32
|
+
wordIntervalMs: Schema.optional(Schema.Number.annotations({
|
|
33
|
+
title: "Word interval (ms)",
|
|
34
|
+
description: "Pacing between words when streaming word-by-word."
|
|
35
|
+
})).pipe(Schema.withConstructorDefault(() => 80))
|
|
16
36
|
}));
|
|
17
37
|
|
|
18
38
|
// src/types/TranscriptionCapabilities.ts
|
|
19
39
|
var TranscriptionCapabilities_exports = {};
|
|
20
40
|
__export(TranscriptionCapabilities_exports, {
|
|
41
|
+
EntityLookup: () => EntityLookup,
|
|
42
|
+
PipelineStatus: () => PipelineStatus,
|
|
43
|
+
RecordingSession: () => RecordingSession,
|
|
21
44
|
Settings: () => Settings2,
|
|
22
|
-
TranscriberProvider: () => TranscriberProvider,
|
|
23
45
|
TranscriptionManagerProvider: () => TranscriptionManagerProvider
|
|
24
46
|
});
|
|
25
47
|
import { Capability } from "@dxos/app-framework";
|
|
26
48
|
import { meta } from "#meta";
|
|
27
|
-
var TranscriberProvider = Capability.make(`${meta.profile.key}.capability.transcriber`);
|
|
28
49
|
var TranscriptionManagerProvider = Capability.make(`${meta.profile.key}.capability.transcription-manager`);
|
|
29
50
|
var Settings2 = Capability.make(`${meta.profile.key}.capability.settings`);
|
|
51
|
+
var RecordingSession = Capability.make(`${meta.profile.key}.capability.recording-session`);
|
|
52
|
+
var EntityLookup = Capability.make(`${meta.profile.key}.capability.entity-lookup`);
|
|
53
|
+
var PipelineStatus = Capability.make(`${meta.profile.key}.capability.pipeline-status`);
|
|
30
54
|
|
|
31
55
|
// src/types/TranscriptOperation.ts
|
|
32
56
|
var TranscriptOperation_exports = {};
|
|
@@ -44,7 +68,7 @@ import * as Schema2 from "effect/Schema";
|
|
|
44
68
|
import { AiService } from "@dxos/ai";
|
|
45
69
|
import { SpaceSchema } from "@dxos/client/echo";
|
|
46
70
|
import { Operation } from "@dxos/compute";
|
|
47
|
-
import { Database,
|
|
71
|
+
import { Database, DXN, Ref, Type } from "@dxos/echo";
|
|
48
72
|
import { Message, Transcript } from "@dxos/types";
|
|
49
73
|
import { meta as meta2 } from "#meta";
|
|
50
74
|
var makeKey = (name) => DXN.make(`${meta2.profile.key}.operation.${name}`);
|
|
@@ -83,8 +107,7 @@ var Open = Operation.make({
|
|
|
83
107
|
content: Schema2.String
|
|
84
108
|
}),
|
|
85
109
|
services: [
|
|
86
|
-
Database.Service
|
|
87
|
-
Feed.FeedService
|
|
110
|
+
Database.Service
|
|
88
111
|
]
|
|
89
112
|
});
|
|
90
113
|
var Summarize = Operation.make({
|
|
@@ -110,7 +133,7 @@ var Summarize = Operation.make({
|
|
|
110
133
|
services: [
|
|
111
134
|
AiService.AiService
|
|
112
135
|
]
|
|
113
|
-
});
|
|
136
|
+
}).pipe(Operation.visible);
|
|
114
137
|
var EnrichMessage = Operation.make({
|
|
115
138
|
meta: {
|
|
116
139
|
key: DXN.make("org.dxos.function.transcription.enrichMessage"),
|
|
@@ -156,4 +179,4 @@ export {
|
|
|
156
179
|
TranscriptionCapabilities_exports,
|
|
157
180
|
TranscriptOperation_exports
|
|
158
181
|
};
|
|
159
|
-
//# sourceMappingURL=chunk-
|
|
182
|
+
//# sourceMappingURL=chunk-MDV7NBFJ.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/types/Settings.ts", "../../../src/types/TranscriptionCapabilities.ts", "../../../src/types/TranscriptOperation.ts"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nexport type RecordMode = 'toggle' | 'hold';\n\nexport const Settings = Schema.mutable(\n Schema.Struct({\n entityExtraction: Schema.optional(\n Schema.Boolean.annotations({\n title: 'Entity extraction',\n description:\n 'While transcribing, use the Assistant to detect and annotate mentions of known objects such as people or organizations.',\n }),\n ).pipe(Schema.withConstructorDefault(() => true)),\n\n recordMode: Schema.optional(\n Schema.Literal('toggle', 'hold').annotations({\n title: 'Record mode',\n description:\n 'Whether the mic toggles recording on each click, or records only while the control is held (push-to-talk).',\n }),\n ).pipe(Schema.withConstructorDefault(() => 'toggle' as const)),\n\n audioDeviceId: Schema.optional(\n Schema.String.annotations({\n title: 'Audio input device',\n description: 'Identifier of the microphone to capture from; empty uses the system default.',\n }),\n ),\n\n transcribeAfterMs: Schema.optional(\n Schema.Number.annotations({\n title: 'Initial buffering (ms)',\n description: 'How long to accumulate audio before producing the first transcription.',\n }),\n ).pipe(Schema.withConstructorDefault(() => 4000)),\n\n streamMode: Schema.optional(\n Schema.Literal('batch', 'word').annotations({\n title: 'Reveal mode',\n description: 'Whether transcribed text appears in batches or streams word-by-word.',\n }),\n ).pipe(Schema.withConstructorDefault(() => 'word' as const)),\n\n wordIntervalMs: Schema.optional(\n Schema.Number.annotations({\n title: 'Word interval (ms)',\n description: 'Pacing between words when streaming word-by-word.',\n }),\n ).pipe(Schema.withConstructorDefault(() => 80)),\n }),\n);\n\nexport interface Settings extends Schema.Schema.Type<typeof Settings> {}\n", "//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport { type Atom } from '@effect-atom/atom-react';\n\nimport { Capability } from '@dxos/app-framework';\nimport { type Space } from '@dxos/client/echo';\nimport { type Feed } from '@dxos/echo';\nimport { type EntityLookup as EntityLookupFn } from '@dxos/transcription-pipeline';\nimport { type Message } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nimport * as SettingsModule from './Settings';\n\n/**\n * Enriches a transcript message before it is written to the feed (e.g. entity linking).\n */\nexport type TranscriptMessageEnricher = (message: Message.Message) => Promise<Message.Message>;\n\n/**\n * Service contract for the meeting transcription manager. Consumers (e.g. plugin-meeting) depend on\n * this interface via the {@link TranscriptionManagerProvider} capability, not on the concrete\n * implementation, keeping the manager's browser/SDK dependencies out of consumer packages.\n */\nexport interface TranscriptionManager {\n readonly enabled: Atom.Atom<boolean>;\n setFeed(space: Space, feed: Feed.Feed): void;\n setAudioTrack(track?: MediaStreamTrack): Promise<void>;\n setRecording(recording?: boolean): void;\n setEnabled(enabled: boolean): Promise<void>;\n open(): Promise<this>;\n close(): Promise<this>;\n}\n\nexport type TranscriptionManagerProviderProps = {\n messageEnricher?: TranscriptMessageEnricher;\n};\n\nexport type TranscriptionManagerProvider = (props: TranscriptionManagerProviderProps) => TranscriptionManager;\n\nexport const TranscriptionManagerProvider = Capability.make<TranscriptionManagerProvider>(\n `${meta.profile.key}.capability.transcription-manager`,\n);\n\nexport const Settings = Capability.make<Atom.Writable<SettingsModule.Settings>>(\n `${meta.profile.key}.capability.settings`,\n);\n\n/**\n * The single active editor transcription session. `id` is the editor's attendable id (the key it\n * registered under in `MarkdownCapabilities.EditorViews`); `recording` gates audio capture. `null`\n * when no session is active.\n */\nexport type RecordingSession = { id: string; recording: boolean };\n\nexport const RecordingSession = Capability.make<Atom.Writable<RecordingSession | null>>(\n `${meta.profile.key}.capability.recording-session`,\n);\n\n/**\n * Resolves entity references for live-transcription enrichment. Backend-agnostic (full-text, vector,\n * a remote service, …) so the headless driver depends on the function, not the database.\n */\nexport type EntityLookup = EntityLookupFn;\n\nexport const EntityLookup = Capability.make<EntityLookupFn>(`${meta.profile.key}.capability.entity-lookup`);\n\n/**\n * Live transcription lifecycle, published by the driver for observers (toolbar spinner, testbench):\n * `recording` (mic capturing) → `draining` (mic off, finishing the pipeline) → `idle`.\n */\nexport type PipelinePhase = 'idle' | 'recording' | 'draining';\n\nexport const PipelineStatus = Capability.make<Atom.Writable<{ phase: PipelinePhase }>>(\n `${meta.profile.key}.capability.pipeline-status`,\n);\n", "//\n// Copyright 2025 DXOS.org\n//\n\n// @import-as-namespace\n\nimport * as Schema from 'effect/Schema';\n\nimport { AiService } from '@dxos/ai';\nimport { SpaceSchema } from '@dxos/client/echo';\nimport { Operation } from '@dxos/compute';\nimport { Database, DXN, Ref, Type } from '@dxos/echo';\n// Message and Person are used via Type.getSchema(Message.Message); they also appear in emitted .d.ts.\n// eslint-disable-next-line unused-imports/no-unused-imports\nimport { Message, type Person, Transcript } from '@dxos/types';\n\nimport { meta } from '#meta';\n\nconst makeKey = (name: string) => DXN.make(`${meta.profile.key}.operation.${name}`);\n\nexport const Create = Operation.make({\n meta: { key: makeKey('create'), name: 'Create Transcript', icon: 'ph--microphone--regular' },\n input: Schema.Struct({\n name: Schema.optional(Schema.String),\n space: SpaceSchema,\n }),\n output: Schema.Struct({\n object: Type.getSchema(Transcript.Transcript),\n }),\n});\n\nexport const MessageWithRangeId = Schema.extend(\n Type.getSchema(Message.Message),\n Schema.Struct({\n rangeId: Schema.optional(Schema.Array(Schema.String)).annotations({\n description: 'The IDs of the messages that contain the sentences.',\n }),\n }),\n);\n\nexport type MessageWithRangeIdType = Schema.Schema.Type<typeof MessageWithRangeId>;\n\nexport const Open = Operation.make({\n meta: {\n key: DXN.make('org.dxos.function.transcription.open'),\n name: 'Open',\n description: 'Opens and reads the contents of a transcription object.',\n icon: 'ph--folder-open--regular',\n },\n input: Schema.Struct({\n transcript: Ref.Ref(Transcript.Transcript).annotations({\n description: 'The ID of the transcription object.',\n }),\n }),\n output: Schema.Struct({\n content: Schema.String,\n }),\n services: [Database.Service],\n});\n\nexport const Summarize = Operation.make({\n meta: {\n key: DXN.make('org.dxos.function.transcription.summarize'),\n name: 'Summarize',\n description: 'Summarize a transcript of a meeting.',\n icon: 'ph--text-align-left--regular',\n },\n input: Schema.Struct({\n transcript: Schema.String.annotations({\n description: 'The transcript of the meeting.',\n }),\n notes: Schema.optional(Schema.String).annotations({\n description: 'Additional notes from the participants.',\n }),\n }),\n output: Schema.Struct({\n summary: Schema.String.annotations({\n description: 'The summary of the transcript.',\n }),\n }),\n services: [AiService.AiService],\n}).pipe(Operation.visible);\n\nexport const EnrichMessage = Operation.make({\n meta: {\n key: DXN.make('org.dxos.function.transcription.enrichMessage'),\n name: 'Enrich Transcript Message',\n description: 'Extract proper nouns from a transcript message and link them to objects in the space.',\n icon: 'ph--text-t--regular',\n },\n input: Schema.Struct({\n message: Type.getSchema(Message.Message),\n }),\n output: Schema.Struct({\n message: Type.getSchema(Message.Message),\n }),\n services: [AiService.AiService, Database.Service],\n});\n\nexport const SentenceNormalizationInput = Schema.Struct({\n messages: Schema.Array(MessageWithRangeId).annotations({\n description: 'Messages to normalize into sentences.',\n }),\n});\n\nexport type SentenceNormalizationInputType = Schema.Schema.Type<typeof SentenceNormalizationInput>;\n\nexport const SentenceNormalizationOutput = Schema.Struct({\n sentences: Schema.Array(MessageWithRangeId.pipe(Schema.mutable)).pipe(Schema.mutable).annotations({\n description: 'The sentences of the transcript.',\n }),\n});\n\nexport const SentenceNormalization = Operation.make({\n meta: {\n key: DXN.make('org.dxos.function.transcription.sentenceNormalization'),\n name: 'Sentence Normalization',\n description: 'Post process of transcription for sentence normalization',\n icon: 'ph--text-t--regular',\n },\n input: SentenceNormalizationInput,\n output: SentenceNormalizationOutput,\n services: [],\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["Schema", "Settings", "mutable", "Struct", "entityExtraction", "optional", "Boolean", "annotations", "title", "description", "pipe", "withConstructorDefault", "recordMode", "Literal", "audioDeviceId", "String", "transcribeAfterMs", "Number", "streamMode", "wordIntervalMs", "Settings", "Capability", "meta", "TranscriptionManagerProvider", "make", "profile", "key", "RecordingSession", "EntityLookup", "PipelineStatus", "Schema", "AiService", "SpaceSchema", "Operation", "Database", "DXN", "Ref", "Type", "Message", "Transcript", "meta", "makeKey", "name", "make", "profile", "key", "Create", "icon", "input", "Struct", "optional", "String", "space", "output", "object", "getSchema", "MessageWithRangeId", "extend", "rangeId", "Array", "annotations", "description", "Open", "transcript", "content", "services", "Service", "Summarize", "notes", "summary", "pipe", "visible", "EnrichMessage", "message", "SentenceNormalizationInput", "messages", "SentenceNormalizationOutput", "sentences", "mutable", "SentenceNormalization"]
|
|
7
|
+
}
|
|
@@ -1,269 +1,125 @@
|
|
|
1
|
-
import {
|
|
2
|
-
DocumentAdapter
|
|
3
|
-
} from "../chunk-MLRJWAQH.mjs";
|
|
4
1
|
import "../chunk-J5LGTIGS.mjs";
|
|
5
2
|
|
|
6
|
-
// src/components/
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import
|
|
10
|
-
import "@dxos/react-ui-
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
3
|
+
// src/components/Mic/Mic.tsx
|
|
4
|
+
import React, { useCallback, useEffect, useRef, useState } from "react";
|
|
5
|
+
import { useAtomCapabilityState } from "@dxos/app-framework/ui";
|
|
6
|
+
import { MicButton, useTranslation } from "@dxos/react-ui";
|
|
7
|
+
import { useSoundEffect } from "@dxos/react-ui-audio";
|
|
8
|
+
import { MicSettings } from "@dxos/react-ui-transcription";
|
|
9
|
+
import { meta } from "#meta";
|
|
10
|
+
import { TranscriptionCapabilities } from "#types";
|
|
11
|
+
var Mic = ({ docId }) => {
|
|
12
|
+
const { t } = useTranslation(meta.profile.key);
|
|
13
|
+
const [session, setSession] = useAtomCapabilityState(TranscriptionCapabilities.RecordingSession);
|
|
14
|
+
const [settings, setSettings] = useAtomCapabilityState(TranscriptionCapabilities.Settings);
|
|
15
|
+
const recording = !!session?.recording && session.id === docId;
|
|
16
|
+
const soundStart = useSoundEffect("StartRecording");
|
|
17
|
+
const soundStop = useSoundEffect("StopRecording");
|
|
18
|
+
const wasRecording = useRef(recording);
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (wasRecording.current === recording) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
wasRecording.current = recording;
|
|
24
|
+
void (recording ? soundStart : soundStop).play();
|
|
25
|
+
}, [
|
|
26
|
+
recording,
|
|
27
|
+
soundStart,
|
|
28
|
+
soundStop
|
|
30
29
|
]);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
Content.displayName = "Oracle.Content";
|
|
45
|
-
var Canvas = ({ classNames, children }) => /* @__PURE__ */ React.createElement(SVG.Root, {
|
|
46
|
-
centered: true,
|
|
47
|
-
classNames: mx("absolute inset-0", classNames)
|
|
48
|
-
}, children ?? /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(SVG.Markers, null), /* @__PURE__ */ React.createElement(SVG.Grid, null), /* @__PURE__ */ React.createElement(SVG.Zoom, {
|
|
49
|
-
extent: [
|
|
50
|
-
1 / 4,
|
|
51
|
-
4
|
|
52
|
-
]
|
|
53
|
-
}, /* @__PURE__ */ React.createElement(SVG.Graph, null))));
|
|
54
|
-
var Text = ({ classNames }) => {
|
|
55
|
-
const { text, delay } = useOracleContext("Text");
|
|
56
|
-
return /* @__PURE__ */ React.createElement("div", {
|
|
57
|
-
className: "pointer-events-none absolute inset-0 flex items-center justify-center"
|
|
58
|
-
}, /* @__PURE__ */ React.createElement(TextBlock, {
|
|
59
|
-
classNames: mx("max-w-xl px-6 py-4 text-center text-2xl font-medium text-balance text-subdued", classNames),
|
|
60
|
-
text,
|
|
61
|
-
delay
|
|
62
|
-
}));
|
|
63
|
-
};
|
|
64
|
-
var Oracle = {
|
|
65
|
-
Root,
|
|
66
|
-
Content,
|
|
67
|
-
Canvas,
|
|
68
|
-
Text
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// src/components/Transcription/Transcription.tsx
|
|
72
|
-
import React2 from "react";
|
|
73
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
74
|
-
import { composable, composableProps as composableProps2 } from "@dxos/react-ui";
|
|
75
|
-
import { useTextEditor } from "@dxos/react-ui-editor";
|
|
76
|
-
import { createBasicExtensions, createMarkdownExtensions, createThemeExtensions, decorateMarkdown, documentSlots, preview, scroller } from "@dxos/ui-editor";
|
|
77
|
-
|
|
78
|
-
// src/components/Transcription/transcription-extension.ts
|
|
79
|
-
import { RangeSetBuilder } from "@codemirror/state";
|
|
80
|
-
import { EditorView, GutterMarker, ViewPlugin, gutter } from "@codemirror/view";
|
|
81
|
-
import { format } from "date-fns/format";
|
|
82
|
-
import { intervalToDuration } from "date-fns/intervalToDuration";
|
|
83
|
-
import { addEventListener, combine } from "@dxos/async";
|
|
84
|
-
var transcription = ({ model, started }) => {
|
|
85
|
-
return [
|
|
86
|
-
// Show timestamps in the gutter.
|
|
87
|
-
gutter({
|
|
88
|
-
class: "cm-timestamp-gutter",
|
|
89
|
-
lineMarkerChange: (update) => update.docChanged || update.viewportChanged,
|
|
90
|
-
markers: (view) => {
|
|
91
|
-
const start = getStartTime(started, model.chunks[0]);
|
|
92
|
-
const builder = new RangeSetBuilder();
|
|
93
|
-
for (const { from, to } of view.visibleRanges) {
|
|
94
|
-
let line = view.state.doc.lineAt(from);
|
|
95
|
-
while (line.from <= to) {
|
|
96
|
-
const block = model.getChunkAtLine(line.number)?.blocks[0];
|
|
97
|
-
const timestamp = block?._tag === "transcript" && block.started;
|
|
98
|
-
if (timestamp) {
|
|
99
|
-
builder.add(line.from, line.from, new TimestampMarker(line.number, new Date(timestamp), start));
|
|
100
|
-
}
|
|
101
|
-
if (line.to + 1 > view.state.doc.length) {
|
|
102
|
-
break;
|
|
103
|
-
}
|
|
104
|
-
line = view.state.doc.lineAt(line.to + 1);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return builder.finish();
|
|
108
|
-
}
|
|
109
|
-
}),
|
|
110
|
-
// Listen for model updates.
|
|
111
|
-
ViewPlugin.fromClass(class {
|
|
112
|
-
_controls;
|
|
113
|
-
_cleanup;
|
|
114
|
-
_adapter;
|
|
115
|
-
_initialized = false;
|
|
116
|
-
constructor(view) {
|
|
117
|
-
this._adapter = new DocumentAdapter(view);
|
|
118
|
-
const scroller2 = view.scrollDOM;
|
|
119
|
-
let isAutoScrolling = false;
|
|
120
|
-
let hasScrolled = false;
|
|
121
|
-
let timeout;
|
|
122
|
-
const scrollToBottom = (smooth = false) => {
|
|
123
|
-
scroller2.style.scrollBehavior = smooth ? "smooth" : "";
|
|
124
|
-
scroller2.classList.add("cm-hide-scrollbar");
|
|
125
|
-
isAutoScrolling = true;
|
|
126
|
-
clearTimeout(timeout);
|
|
127
|
-
timeout = setTimeout(() => {
|
|
128
|
-
this._controls?.classList.add("opacity-0");
|
|
129
|
-
scroller2.classList.remove("cm-hide-scrollbar");
|
|
130
|
-
isAutoScrolling = false;
|
|
131
|
-
}, 500);
|
|
132
|
-
view.dispatch({
|
|
133
|
-
effects: EditorView.scrollIntoView(view.state.doc.length, {
|
|
134
|
-
y: "end"
|
|
135
|
-
})
|
|
136
|
-
});
|
|
137
|
-
};
|
|
138
|
-
this._cleanup = combine(addEventListener(view.scrollDOM, "scroll", () => {
|
|
139
|
-
if (!isAutoScrolling) {
|
|
140
|
-
hasScrolled = true;
|
|
141
|
-
this._controls?.classList.remove("opacity-0");
|
|
142
|
-
}
|
|
143
|
-
}), model.update.on(() => {
|
|
144
|
-
const autoScroll = scroller2.scrollHeight - scroller2.scrollTop - scroller2.clientHeight === 0 || !hasScrolled;
|
|
145
|
-
model.sync(this._adapter);
|
|
146
|
-
if (autoScroll) {
|
|
147
|
-
scrollToBottom(true);
|
|
148
|
-
}
|
|
149
|
-
}));
|
|
150
|
-
}
|
|
151
|
-
update(_update) {
|
|
152
|
-
if (!this._initialized) {
|
|
153
|
-
this._initialized = true;
|
|
154
|
-
setTimeout(() => {
|
|
155
|
-
model.sync(this._adapter);
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
destroy() {
|
|
160
|
-
this._controls?.remove();
|
|
161
|
-
this._cleanup();
|
|
30
|
+
const recordMode = settings?.recordMode ?? "toggle";
|
|
31
|
+
const entityExtraction = settings?.entityExtraction !== false;
|
|
32
|
+
const selectedDeviceId = settings?.audioDeviceId ?? "";
|
|
33
|
+
const [devices, setDevices] = useState([]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (!navigator.mediaDevices?.enumerateDevices) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let cancelled = false;
|
|
39
|
+
const refresh = async () => {
|
|
40
|
+
const all = await navigator.mediaDevices.enumerateDevices();
|
|
41
|
+
if (cancelled) {
|
|
42
|
+
return;
|
|
162
43
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
},
|
|
168
|
-
".cm-timestamp-gutter": {
|
|
169
|
-
width: "6rem",
|
|
170
|
-
paddingLeft: "0.5rem",
|
|
171
|
-
paddingRight: "1rem"
|
|
172
|
-
},
|
|
173
|
-
".cm-timestamp-gutter > .cm-gutterElement > div": {
|
|
174
|
-
display: "inline-flex",
|
|
175
|
-
textAlign: "right",
|
|
176
|
-
padding: "3px"
|
|
177
|
-
}
|
|
178
|
-
})
|
|
179
|
-
];
|
|
180
|
-
};
|
|
181
|
-
var TimestampMarker = class extends GutterMarker {
|
|
182
|
-
_line;
|
|
183
|
-
_timestamp;
|
|
184
|
-
_started;
|
|
185
|
-
constructor(_line, _timestamp, _started) {
|
|
186
|
-
super(), this._line = _line, this._timestamp = _timestamp, this._started = _started;
|
|
187
|
-
}
|
|
188
|
-
eq(other) {
|
|
189
|
-
return this._timestamp === other._timestamp;
|
|
190
|
-
}
|
|
191
|
-
toDOM(view) {
|
|
192
|
-
const el = document.createElement("div");
|
|
193
|
-
el.className = "text-sm text-subdued hover:bg-hover-surface cursor-pointer";
|
|
194
|
-
el.textContent = formatTimestamp(this._timestamp, this._started);
|
|
195
|
-
el.onclick = () => {
|
|
196
|
-
const pos = view.state.doc.line(this._line).from;
|
|
197
|
-
view.dispatch({
|
|
198
|
-
effects: EditorView.scrollIntoView(pos, {
|
|
199
|
-
y: "start"
|
|
200
|
-
})
|
|
201
|
-
});
|
|
44
|
+
setDevices(all.filter((device) => device.kind === "audioinput" && device.deviceId).map((device, index) => ({
|
|
45
|
+
deviceId: device.deviceId,
|
|
46
|
+
label: device.label || `Microphone ${index + 1}`
|
|
47
|
+
})));
|
|
202
48
|
};
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
return started;
|
|
209
|
-
}
|
|
210
|
-
if (message?.blocks[0]?._tag === "transcript" && message.blocks[0].started) {
|
|
211
|
-
return new Date(message.blocks[0].started);
|
|
212
|
-
}
|
|
213
|
-
return void 0;
|
|
214
|
-
};
|
|
215
|
-
var formatTimestamp = (timestamp, relative) => {
|
|
216
|
-
if (relative) {
|
|
217
|
-
const pad = (n = 0) => String(n).padStart(2, "0");
|
|
218
|
-
const { hours, minutes, seconds } = intervalToDuration({
|
|
219
|
-
start: relative,
|
|
220
|
-
end: timestamp
|
|
221
|
-
});
|
|
222
|
-
return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;
|
|
223
|
-
} else {
|
|
224
|
-
return format(timestamp, "HH:mm:ss");
|
|
225
|
-
}
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
// src/components/Transcription/Transcription.tsx
|
|
229
|
-
var Transcription = composable(({ transcript: object, model, children, ...props }, forwardedRef) => {
|
|
230
|
-
const { themeMode } = useThemeContext();
|
|
231
|
-
const { parentRef } = useTextEditor(() => {
|
|
232
|
-
return {
|
|
233
|
-
extensions: [
|
|
234
|
-
createBasicExtensions({
|
|
235
|
-
readOnly: true,
|
|
236
|
-
lineWrapping: true,
|
|
237
|
-
search: true
|
|
238
|
-
}),
|
|
239
|
-
createThemeExtensions({
|
|
240
|
-
themeMode,
|
|
241
|
-
slots: documentSlots
|
|
242
|
-
}),
|
|
243
|
-
createMarkdownExtensions(),
|
|
244
|
-
decorateMarkdown(),
|
|
245
|
-
preview(),
|
|
246
|
-
transcription({
|
|
247
|
-
model,
|
|
248
|
-
started: object?.started ? new Date(object.started) : void 0
|
|
249
|
-
}),
|
|
250
|
-
scroller()
|
|
251
|
-
]
|
|
49
|
+
void refresh();
|
|
50
|
+
navigator.mediaDevices.addEventListener("devicechange", refresh);
|
|
51
|
+
return () => {
|
|
52
|
+
cancelled = true;
|
|
53
|
+
navigator.mediaDevices.removeEventListener("devicechange", refresh);
|
|
252
54
|
};
|
|
55
|
+
}, []);
|
|
56
|
+
const handleToggle = useCallback(() => {
|
|
57
|
+
setSession((current) => current?.recording && current.id === docId ? null : {
|
|
58
|
+
id: docId,
|
|
59
|
+
recording: true
|
|
60
|
+
});
|
|
61
|
+
}, [
|
|
62
|
+
setSession,
|
|
63
|
+
docId
|
|
64
|
+
]);
|
|
65
|
+
const handlePressStart = useCallback(() => {
|
|
66
|
+
setSession(() => ({
|
|
67
|
+
id: docId,
|
|
68
|
+
recording: true
|
|
69
|
+
}));
|
|
253
70
|
}, [
|
|
254
|
-
|
|
255
|
-
|
|
71
|
+
setSession,
|
|
72
|
+
docId
|
|
256
73
|
]);
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
74
|
+
const handlePressEnd = useCallback(() => {
|
|
75
|
+
setSession((current) => current?.id === docId ? null : current);
|
|
76
|
+
}, [
|
|
77
|
+
setSession,
|
|
78
|
+
docId
|
|
79
|
+
]);
|
|
80
|
+
const handleRecordModeChange = useCallback((mode) => setSettings((current) => ({
|
|
81
|
+
...current,
|
|
82
|
+
recordMode: mode
|
|
83
|
+
})), [
|
|
84
|
+
setSettings
|
|
85
|
+
]);
|
|
86
|
+
const handleEntityExtractionChange = useCallback((value) => setSettings((current) => ({
|
|
87
|
+
...current,
|
|
88
|
+
entityExtraction: value
|
|
89
|
+
})), [
|
|
90
|
+
setSettings
|
|
91
|
+
]);
|
|
92
|
+
const handleSelectDevice = useCallback((deviceId) => setSettings((current) => ({
|
|
93
|
+
...current,
|
|
94
|
+
audioDeviceId: deviceId || void 0
|
|
95
|
+
})), [
|
|
96
|
+
setSettings
|
|
97
|
+
]);
|
|
98
|
+
const recordLabel = recording ? t("stop-recording.label") : recordMode === "hold" ? t("hold-to-record.label") : t("start-recording.label");
|
|
99
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
100
|
+
className: "flex items-center"
|
|
101
|
+
}, /* @__PURE__ */ React.createElement(MicButton, {
|
|
102
|
+
iconOnly: true,
|
|
103
|
+
variant: "ghost",
|
|
104
|
+
label: recordLabel,
|
|
105
|
+
recording,
|
|
106
|
+
mode: recordMode,
|
|
107
|
+
onToggle: handleToggle,
|
|
108
|
+
onPressStart: handlePressStart,
|
|
109
|
+
onPressEnd: handlePressEnd,
|
|
110
|
+
"data-testid": "transcription.record"
|
|
111
|
+
}), /* @__PURE__ */ React.createElement(MicSettings, {
|
|
112
|
+
translationNs: meta.profile.key,
|
|
113
|
+
recordMode,
|
|
114
|
+
entityExtraction,
|
|
115
|
+
devices,
|
|
116
|
+
selectedDeviceId,
|
|
117
|
+
onRecordModeChange: handleRecordModeChange,
|
|
118
|
+
onEntityExtractionChange: handleEntityExtractionChange,
|
|
119
|
+
onSelectDevice: handleSelectDevice
|
|
120
|
+
}));
|
|
121
|
+
};
|
|
265
122
|
export {
|
|
266
|
-
|
|
267
|
-
Transcription
|
|
123
|
+
Mic
|
|
268
124
|
};
|
|
269
125
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/components/
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Primitive } from '@radix-ui/react-primitive';\nimport { Slot } from '@radix-ui/react-slot';\nimport React, { type PropsWithChildren, createContext, useContext, useMemo } from 'react';\n\nimport '@dxos/react-ui-graph/styles/graph.css';\nimport { type ThemedClassName } from '@dxos/react-ui';\nimport { composableProps, slottable } from '@dxos/react-ui';\nimport { TextBlock } from '@dxos/react-ui-components';\nimport { SVG } from '@dxos/react-ui-graph';\nimport { mx } from '@dxos/ui-theme';\nimport { type SlottableProps } from '@dxos/ui-types';\n\n//\n// Context\n//\n\ntype OracleContextValue = {\n /** Latest utterance / phrase rendered by `Oracle.Text`. */\n text: string;\n /** Per-character reveal delay in ms for the streaming TextBlock. */\n delay: number;\n};\n\nconst OracleContext = createContext<OracleContextValue | null>(null);\n\nconst useOracleContext = (consumer: string): OracleContextValue => {\n const ctx = useContext(OracleContext);\n if (!ctx) {\n throw new Error(`<Oracle.${consumer}> must be rendered inside <Oracle.Root>`);\n }\n return ctx;\n};\n\n//\n// Root (headless — provides context only, renders no DOM)\n//\n\nexport type OracleRootProps = PropsWithChildren<{\n /** Latest utterance / phrase rendered by `Oracle.Text`. */\n text?: string;\n /** Per-character reveal delay in ms for the streaming TextBlock. @default 12 */\n delay?: number;\n}>;\n\n/**\n * Oracle surface root. Headless — provides text/delay context to subcomponents and renders\n * no DOM of its own. Wrap subcomponents in `<Oracle.Content>` for the standard relative\n * stacking layout, or place `<Oracle.Canvas>` / `<Oracle.Text>` inside any positioned\n * container of your choice.\n */\nconst Root = ({ children, text = '', delay = 12 }: OracleRootProps) => {\n const value = useMemo(() => ({ text, delay }), [text, delay]);\n return <OracleContext.Provider value={value}>{children}</OracleContext.Provider>;\n};\n\n//\n// Content\n//\n\nexport type OracleContentProps = SlottableProps;\n\n/**\n * Positioned container that stacks `Oracle.Canvas` (the SVG graph viewport, absolutely\n * positioned to fill) under `Oracle.Text` (the centered overlay). Use this for the standard\n * Oracle layout; skip it if you need custom positioning.\n *\n * Pass `asChild` to merge the positioning + sizing onto a parent slot (e.g. `Panel.Content`).\n */\nconst Content = slottable<HTMLDivElement>(({ children, asChild, ...props }, forwardedRef) => {\n const Comp = asChild ? Slot : Primitive.div;\n return (\n <Comp {...composableProps(props, { classNames: 'relative dx-expander' })} ref={forwardedRef}>\n {children}\n </Comp>\n );\n});\n\nContent.displayName = 'Oracle.Content';\n\n//\n// Canvas\n//\n\nexport type OracleCanvasProps = ThemedClassName<PropsWithChildren<{}>>;\n\n/**\n * SVG graph viewport. Renders sensible defaults (markers, grid, pan/zoom, empty graph)\n * when no children are supplied; consumers can replace those by passing their own\n * SVG.* children (e.g. a populated `<SVG.Graph model={…} />`).\n */\nconst Canvas = ({ classNames, children }: OracleCanvasProps) => (\n <SVG.Root centered classNames={mx('absolute inset-0', classNames)}>\n {children ?? (\n <>\n <SVG.Markers />\n <SVG.Grid />\n <SVG.Zoom extent={[1 / 4, 4]}>\n <SVG.Graph />\n </SVG.Zoom>\n </>\n )}\n </SVG.Root>\n);\n\n//\n// Text\n//\n\nexport type OracleTextProps = ThemedClassName<{}>;\n\n/**\n * Centered text overlay. Reads `text` and `delay` from `Oracle.Root` context and renders\n * a streaming `TextBlock` floating above the canvas. Pointer-events are disabled so the\n * underlying graph remains interactive.\n */\nconst Text = ({ classNames }: OracleTextProps) => {\n const { text, delay } = useOracleContext('Text');\n return (\n <div className='pointer-events-none absolute inset-0 flex items-center justify-center'>\n <TextBlock\n classNames={mx('max-w-xl px-6 py-4 text-center text-2xl font-medium text-balance text-subdued', classNames)}\n text={text}\n delay={delay}\n />\n </div>\n );\n};\n\n//\n// Namespace\n//\n\nexport const Oracle = {\n Root,\n Content,\n Canvas,\n Text,\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React from 'react';\n\nimport { useThemeContext } from '@dxos/react-ui';\nimport { composable, composableProps } from '@dxos/react-ui';\nimport { useTextEditor } from '@dxos/react-ui-editor';\nimport { type Message, type Transcript } from '@dxos/types';\nimport {\n createBasicExtensions,\n createMarkdownExtensions,\n createThemeExtensions,\n decorateMarkdown,\n documentSlots,\n preview,\n scroller,\n} from '@dxos/ui-editor';\n\nimport { type SerializationModel } from '../../model';\nimport { transcription } from './transcription-extension';\n\nexport type TranscriptionProps = {\n transcript?: Transcript.Transcript;\n model: SerializationModel<Message.Message>;\n};\n\n// TODO(burdon): Remove forwardedRef/use react-ui-editor.\nexport const Transcription = composable<HTMLDivElement, TranscriptionProps>(\n ({ transcript: object, model, children, ...props }, forwardedRef) => {\n const { themeMode } = useThemeContext();\n const { parentRef } = useTextEditor(() => {\n return {\n extensions: [\n createBasicExtensions({ readOnly: true, lineWrapping: true, search: true }),\n createThemeExtensions({ themeMode, slots: documentSlots }),\n createMarkdownExtensions(),\n decorateMarkdown(),\n preview(),\n transcription({ model, started: object?.started ? new Date(object.started) : undefined }),\n scroller(),\n ],\n };\n }, [model, themeMode]);\n\n return (\n <div\n {...composableProps(props, { classNames: 'dx-container' })}\n data-popover-collision-boundary={true}\n ref={parentRef}\n />\n );\n },\n);\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Extension, RangeSetBuilder } from '@codemirror/state';\nimport { EditorView, GutterMarker, ViewPlugin, type ViewUpdate, gutter } from '@codemirror/view';\nimport { format } from 'date-fns/format';\nimport { intervalToDuration } from 'date-fns/intervalToDuration';\n\nimport { type CleanupFn, addEventListener, combine } from '@dxos/async';\nimport { type Message } from '@dxos/types';\n\nimport { DocumentAdapter, type SerializationModel } from '../../model';\n\n/**\n * Data structure that maps Chunks queue to lines with transcript state.\n */\nexport type TranscriptionOptions = {\n model: SerializationModel<Message.Message>;\n started?: Date;\n};\n\n/**\n * Scrolling transcript with timestamps.\n */\nexport const transcription = ({ model, started }: TranscriptionOptions): Extension => {\n return [\n // Show timestamps in the gutter.\n gutter({\n class: 'cm-timestamp-gutter',\n lineMarkerChange: (update) => update.docChanged || update.viewportChanged,\n markers: (view) => {\n const start = getStartTime(started, model.chunks[0]);\n const builder = new RangeSetBuilder<GutterMarker>();\n for (const { from, to } of view.visibleRanges) {\n let line = view.state.doc.lineAt(from);\n while (line.from <= to) {\n const block = model.getChunkAtLine(line.number)?.blocks[0];\n const timestamp = block?._tag === 'transcript' && block.started;\n if (timestamp) {\n builder.add(line.from, line.from, new TimestampMarker(line.number, new Date(timestamp), start));\n }\n\n if (line.to + 1 > view.state.doc.length) {\n break;\n }\n\n line = view.state.doc.lineAt(line.to + 1);\n }\n }\n\n return builder.finish();\n },\n }),\n\n // Listen for model updates.\n ViewPlugin.fromClass(\n class {\n private readonly _controls?: HTMLDivElement;\n private readonly _cleanup: CleanupFn;\n private readonly _adapter: DocumentAdapter;\n private _initialized = false;\n\n constructor(view: EditorView) {\n this._adapter = new DocumentAdapter(view);\n\n const scroller = view.scrollDOM;\n let isAutoScrolling = false;\n let hasScrolled = false;\n\n let timeout: NodeJS.Timeout | undefined;\n const scrollToBottom = (smooth = false) => {\n scroller.style.scrollBehavior = smooth ? 'smooth' : '';\n\n // Temporarily hide scrollbar to prevent flicker.\n scroller.classList.add('cm-hide-scrollbar');\n isAutoScrolling = true;\n clearTimeout(timeout);\n timeout = setTimeout(() => {\n this._controls?.classList.add('opacity-0');\n scroller.classList.remove('cm-hide-scrollbar');\n isAutoScrolling = false;\n }, 500);\n\n // Scroll to bottom.\n view.dispatch({\n effects: EditorView.scrollIntoView(view.state.doc.length, { y: 'end' }),\n });\n };\n\n // Event listeners.\n this._cleanup = combine(\n addEventListener(view.scrollDOM, 'scroll', () => {\n if (!isAutoScrolling) {\n hasScrolled = true;\n this._controls?.classList.remove('opacity-0');\n }\n }),\n\n model.update.on(() => {\n // Check if clamped to bottom.\n const autoScroll =\n scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight === 0 || !hasScrolled;\n\n // Sync.\n model.sync(this._adapter);\n\n // Scroll.\n if (autoScroll) {\n scrollToBottom(true);\n }\n }),\n );\n }\n\n update(_update: ViewUpdate) {\n // Initial sync.\n if (!this._initialized) {\n this._initialized = true;\n setTimeout(() => {\n model.sync(this._adapter);\n });\n }\n }\n\n destroy() {\n this._controls?.remove();\n this._cleanup();\n }\n },\n ),\n\n EditorView.theme({\n '.cm-gutters': {\n backgroundColor: 'var(--color-base-surface)',\n },\n '.cm-timestamp-gutter': {\n width: '6rem',\n paddingLeft: '0.5rem',\n paddingRight: '1rem',\n },\n '.cm-timestamp-gutter > .cm-gutterElement > div': {\n display: 'inline-flex',\n textAlign: 'right',\n padding: '3px',\n },\n }),\n ];\n};\n\n/**\n * Gutter marker that displays a timestamp.\n */\nclass TimestampMarker extends GutterMarker {\n constructor(\n readonly _line: number,\n readonly _timestamp: Date,\n readonly _started?: Date,\n ) {\n super();\n }\n\n override eq(other: this) {\n return this._timestamp === other._timestamp;\n }\n\n override toDOM(view: EditorView) {\n const el = document.createElement('div');\n el.className = 'text-sm text-subdued hover:bg-hover-surface cursor-pointer';\n el.textContent = formatTimestamp(this._timestamp, this._started);\n // TODO(burdon): Click to bookmark or copy hyperlink.\n el.onclick = () => {\n const pos = view.state.doc.line(this._line).from;\n view.dispatch({\n effects: EditorView.scrollIntoView(pos, { y: 'start' }),\n });\n };\n\n return el;\n }\n}\n\nconst getStartTime = (started?: Date, message?: Message.Message): Date | undefined => {\n if (started) {\n return started;\n }\n\n if (message?.blocks[0]?._tag === 'transcript' && message.blocks[0].started) {\n return new Date(message.blocks[0].started);\n }\n\n return undefined;\n};\n\nconst formatTimestamp = (timestamp: Date, relative?: Date) => {\n if (relative) {\n const pad = (n = 0) => String(n).padStart(2, '0');\n const { hours, minutes, seconds } = intervalToDuration({ start: relative, end: timestamp });\n return `${pad(hours)}:${pad(minutes)}:${pad(seconds)}`;\n } else {\n return format(timestamp, 'HH:mm:ss');\n }\n};\n"],
|
|
5
|
-
"mappings": "
|
|
6
|
-
"names": ["
|
|
3
|
+
"sources": ["../../../../src/components/Mic/Mic.tsx"],
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { useAtomCapabilityState } from '@dxos/app-framework/ui';\nimport { MicButton, useTranslation } from '@dxos/react-ui';\nimport { useSoundEffect } from '@dxos/react-ui-audio';\nimport { type AudioInputDevice, MicSettings } from '@dxos/react-ui-transcription';\n\nimport { meta } from '#meta';\nimport { type Settings, TranscriptionCapabilities } from '#types';\n\nexport type MicProps = {\n /** Attendable id of the target editor; keys the recording session. */\n docId: string;\n};\n\n/**\n * Connects the {@link MicButton} and {@link MicSettings} to the recording session and settings\n * capabilities, and enumerates available audio inputs. Mounted from the toolbar's custom action, so\n * capability hooks resolve.\n */\nexport const Mic = ({ docId }: MicProps) => {\n const { t } = useTranslation(meta.profile.key);\n const [session, setSession] = useAtomCapabilityState(TranscriptionCapabilities.RecordingSession);\n const [settings, setSettings] = useAtomCapabilityState(TranscriptionCapabilities.Settings);\n\n const recording = !!session?.recording && session.id === docId;\n\n // Play start/stop cues as this session's recording flag flips (skip the initial mount).\n const soundStart = useSoundEffect('StartRecording');\n const soundStop = useSoundEffect('StopRecording');\n const wasRecording = useRef(recording);\n useEffect(() => {\n if (wasRecording.current === recording) {\n return;\n }\n wasRecording.current = recording;\n void (recording ? soundStart : soundStop).play();\n }, [recording, soundStart, soundStop]);\n\n const recordMode: Settings.RecordMode = settings?.recordMode ?? 'toggle';\n const entityExtraction = settings?.entityExtraction !== false;\n const selectedDeviceId = settings?.audioDeviceId ?? '';\n\n const [devices, setDevices] = useState<AudioInputDevice[]>([]);\n useEffect(() => {\n if (!navigator.mediaDevices?.enumerateDevices) {\n return;\n }\n let cancelled = false;\n const refresh = async () => {\n const all = await navigator.mediaDevices.enumerateDevices();\n if (cancelled) {\n return;\n }\n // Labels are blank until microphone permission is granted; fall back to an ordinal name.\n setDevices(\n all\n .filter((device) => device.kind === 'audioinput' && device.deviceId)\n .map((device, index) => ({\n deviceId: device.deviceId,\n label: device.label || `Microphone ${index + 1}`,\n })),\n );\n };\n void refresh();\n navigator.mediaDevices.addEventListener('devicechange', refresh);\n return () => {\n cancelled = true;\n navigator.mediaDevices.removeEventListener('devicechange', refresh);\n };\n }, []);\n\n const handleToggle = useCallback(() => {\n setSession((current) => (current?.recording && current.id === docId ? null : { id: docId, recording: true }));\n }, [setSession, docId]);\n\n const handlePressStart = useCallback(() => {\n setSession(() => ({ id: docId, recording: true }));\n }, [setSession, docId]);\n\n const handlePressEnd = useCallback(() => {\n // Only stop our own session; a stray release must not clear another editor's recording.\n setSession((current) => (current?.id === docId ? null : current));\n }, [setSession, docId]);\n\n const handleRecordModeChange = useCallback(\n (mode: Settings.RecordMode) => setSettings((current) => ({ ...current, recordMode: mode })),\n [setSettings],\n );\n\n const handleEntityExtractionChange = useCallback(\n (value: boolean) => setSettings((current) => ({ ...current, entityExtraction: value })),\n [setSettings],\n );\n\n const handleSelectDevice = useCallback(\n (deviceId: string) => setSettings((current) => ({ ...current, audioDeviceId: deviceId || undefined })),\n [setSettings],\n );\n\n const recordLabel = recording\n ? t('stop-recording.label')\n : recordMode === 'hold'\n ? t('hold-to-record.label')\n : t('start-recording.label');\n\n return (\n <div className='flex items-center'>\n <MicButton\n iconOnly\n variant='ghost'\n label={recordLabel}\n recording={recording}\n mode={recordMode}\n onToggle={handleToggle}\n onPressStart={handlePressStart}\n onPressEnd={handlePressEnd}\n data-testid='transcription.record'\n />\n <MicSettings\n translationNs={meta.profile.key}\n recordMode={recordMode}\n entityExtraction={entityExtraction}\n devices={devices}\n selectedDeviceId={selectedDeviceId}\n onRecordModeChange={handleRecordModeChange}\n onEntityExtractionChange={handleEntityExtractionChange}\n onSelectDevice={handleSelectDevice}\n />\n </div>\n );\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["React", "useCallback", "useEffect", "useRef", "useState", "useAtomCapabilityState", "MicButton", "useTranslation", "useSoundEffect", "MicSettings", "meta", "TranscriptionCapabilities", "Mic", "docId", "t", "profile", "key", "session", "setSession", "RecordingSession", "settings", "setSettings", "Settings", "recording", "id", "soundStart", "soundStop", "wasRecording", "current", "play", "recordMode", "entityExtraction", "selectedDeviceId", "audioDeviceId", "devices", "setDevices", "navigator", "mediaDevices", "enumerateDevices", "cancelled", "refresh", "all", "filter", "device", "kind", "deviceId", "map", "index", "label", "addEventListener", "removeEventListener", "handleToggle", "handlePressStart", "handlePressEnd", "handleRecordModeChange", "mode", "handleEntityExtractionChange", "value", "handleSelectDevice", "undefined", "recordLabel", "div", "className", "iconOnly", "variant", "onToggle", "onPressStart", "onPressEnd", "data-testid", "translationNs", "onRecordModeChange", "onEntityExtractionChange", "onSelectDevice"]
|
|
7
7
|
}
|
|
@@ -2,7 +2,7 @@ import "../chunk-J5LGTIGS.mjs";
|
|
|
2
2
|
|
|
3
3
|
// src/containers/index.ts
|
|
4
4
|
import { lazy } from "react";
|
|
5
|
-
var TranscriptionArticle = lazy(() => import("../TranscriptionArticle-
|
|
5
|
+
var TranscriptionArticle = lazy(() => import("../TranscriptionArticle-FEWCWG4A.mjs"));
|
|
6
6
|
export {
|
|
7
7
|
TranscriptionArticle
|
|
8
8
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TranscriptOperation_exports
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MDV7NBFJ.mjs";
|
|
4
4
|
import "./chunk-J5LGTIGS.mjs";
|
|
5
5
|
|
|
6
6
|
// src/operations/create.ts
|
|
@@ -18,4 +18,4 @@ var create_default = handler;
|
|
|
18
18
|
export {
|
|
19
19
|
create_default as default
|
|
20
20
|
};
|
|
21
|
-
//# sourceMappingURL=create-
|
|
21
|
+
//# sourceMappingURL=create-HNHGCKZ4.mjs.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TranscriptOperation_exports
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-MDV7NBFJ.mjs";
|
|
4
4
|
import "./chunk-J5LGTIGS.mjs";
|
|
5
5
|
|
|
6
6
|
// src/operations/enrich-message.ts
|
|
@@ -21,4 +21,4 @@ var enrich_message_default = handler;
|
|
|
21
21
|
export {
|
|
22
22
|
enrich_message_default as default
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=enrich-message-
|
|
24
|
+
//# sourceMappingURL=enrich-message-DSJU4TXC.mjs.map
|