@dxos/plugin-transcription 0.8.4-main.28f8d3d → 0.8.4-main.406dc2a
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/dist/lib/browser/TranscriptContainer-QN5WUMWJ.mjs +11 -0
- package/dist/lib/browser/blueprint-definition-GO6GTEBT.mjs +150 -0
- package/dist/lib/browser/blueprint-definition-GO6GTEBT.mjs.map +7 -0
- package/dist/lib/browser/{chunk-UKUSJTQW.mjs → chunk-77NWYLC6.mjs} +2 -2
- package/dist/lib/browser/{chunk-5WH45KBY.mjs → chunk-7LNCQDTT.mjs} +9 -4
- package/dist/lib/browser/chunk-7LNCQDTT.mjs.map +7 -0
- package/dist/lib/browser/{chunk-KJIQQHJB.mjs → chunk-COBQIZ6B.mjs} +78 -98
- package/dist/lib/browser/{chunk-KJIQQHJB.mjs.map → chunk-COBQIZ6B.mjs.map} +3 -3
- package/dist/lib/browser/chunk-GGHMOEKZ.mjs +63 -0
- package/dist/lib/browser/chunk-GGHMOEKZ.mjs.map +7 -0
- package/dist/lib/browser/{chunk-SREIAQSP.mjs → chunk-LCK3YRQF.mjs} +5 -5
- package/dist/lib/browser/chunk-LCK3YRQF.mjs.map +7 -0
- package/dist/lib/browser/{chunk-BJWYA2BU.mjs → chunk-ZS2FXKEF.mjs} +141 -168
- package/dist/lib/browser/chunk-ZS2FXKEF.mjs.map +7 -0
- package/dist/lib/browser/index.mjs +22 -18
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/intent-resolver-52EPFRMR.mjs +25 -0
- package/dist/lib/browser/intent-resolver-52EPFRMR.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/{react-surface-4MEJMKYQ.mjs → react-surface-LCP2D2MF.mjs} +10 -10
- package/dist/lib/browser/react-surface-LCP2D2MF.mjs.map +7 -0
- package/dist/lib/browser/{transcriber-V77CN7XX.mjs → transcriber-NG5MRCP6.mjs} +7 -7
- package/dist/lib/browser/{transcriber-V77CN7XX.mjs.map → transcriber-NG5MRCP6.mjs.map} +1 -1
- package/dist/lib/browser/types/index.mjs +6 -8
- package/dist/lib/node-esm/{TranscriptContainer-GEUOOYHX.mjs → TranscriptContainer-WCUWVVSD.mjs} +4 -4
- package/dist/lib/node-esm/blueprint-definition-6SU7GLBR.mjs +151 -0
- package/dist/lib/node-esm/blueprint-definition-6SU7GLBR.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-A33GNR44.mjs → chunk-A6SB234F.mjs} +78 -98
- package/dist/lib/node-esm/{chunk-A33GNR44.mjs.map → chunk-A6SB234F.mjs.map} +3 -3
- package/dist/lib/node-esm/chunk-FTTZ4YSX.mjs +64 -0
- package/dist/lib/node-esm/chunk-FTTZ4YSX.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-XMUCZBP3.mjs → chunk-KLTPFUKN.mjs} +8 -4
- package/dist/lib/node-esm/chunk-KLTPFUKN.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-PHP7MCAY.mjs → chunk-N5Z4SKPH.mjs} +2 -2
- package/dist/lib/node-esm/{chunk-Y7PCJ34K.mjs → chunk-PEZRQYKO.mjs} +141 -168
- package/dist/lib/node-esm/chunk-PEZRQYKO.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-TM2ASOZA.mjs → chunk-RWRG3S2O.mjs} +5 -5
- package/dist/lib/node-esm/chunk-RWRG3S2O.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +22 -18
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/intent-resolver-DZBQQRHN.mjs +26 -0
- package/dist/lib/node-esm/intent-resolver-DZBQQRHN.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/{react-surface-EZUPNHUC.mjs → react-surface-7UC2YXX2.mjs} +10 -10
- package/dist/lib/node-esm/react-surface-7UC2YXX2.mjs.map +7 -0
- package/dist/lib/node-esm/{transcriber-3SX3DNLV.mjs → transcriber-SMU7HD6F.mjs} +7 -7
- package/dist/lib/node-esm/{transcriber-3SX3DNLV.mjs.map → transcriber-SMU7HD6F.mjs.map} +1 -1
- package/dist/lib/node-esm/types/index.mjs +6 -8
- package/dist/types/src/TranscriptionPlugin.d.ts +1 -1
- package/dist/types/src/TranscriptionPlugin.d.ts.map +1 -1
- package/dist/types/src/capabilities/blueprint-definition.d.ts +5 -0
- package/dist/types/src/capabilities/blueprint-definition.d.ts.map +1 -0
- package/dist/types/src/capabilities/capabilities.d.ts.map +1 -1
- package/dist/types/src/capabilities/index.d.ts +3 -2
- package/dist/types/src/capabilities/index.d.ts.map +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts +1 -1
- package/dist/types/src/capabilities/intent-resolver.d.ts.map +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/transcriber.d.ts +1 -1
- package/dist/types/src/components/Transcript/Transcript.d.ts +5 -5
- package/dist/types/src/components/Transcript/Transcript.d.ts.map +1 -1
- package/dist/types/src/components/Transcript/Transcript.stories.d.ts +31 -16
- package/dist/types/src/components/Transcript/Transcript.stories.d.ts.map +1 -1
- package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts +3 -3
- package/dist/types/src/components/Transcript/deprecated/OldTranscript.d.ts.map +1 -1
- package/dist/types/src/components/Transcript/transcript-extension.d.ts +1 -5
- package/dist/types/src/components/Transcript/transcript-extension.d.ts.map +1 -1
- package/dist/types/src/components/TranscriptContainer.d.ts +2 -2
- package/dist/types/src/components/TranscriptContainer.d.ts.map +1 -1
- package/dist/types/src/components/stories/FileTranscription.stories.d.ts +8 -4
- package/dist/types/src/components/stories/FileTranscription.stories.d.ts.map +1 -1
- package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts +13 -6
- package/dist/types/src/components/stories/KeyWordRecognition.stories.d.ts.map +1 -1
- package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts +10 -6
- package/dist/types/src/components/stories/MicrophoneTranscription.stories.d.ts.map +1 -1
- package/dist/types/src/components/stories/TranscriptionStory.d.ts +2 -1
- package/dist/types/src/components/stories/TranscriptionStory.d.ts.map +1 -1
- package/dist/types/src/functions/index.d.ts +3 -0
- package/dist/types/src/functions/index.d.ts.map +1 -0
- package/dist/types/src/functions/open.d.ts +7 -0
- package/dist/types/src/functions/open.d.ts.map +1 -0
- package/dist/types/src/functions/summarize.d.ts +11 -0
- package/dist/types/src/functions/summarize.d.ts.map +1 -0
- package/dist/types/src/hooks/useAudioFile.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +0 -1
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/segments-normalization/normalization.d.ts +376 -331
- package/dist/types/src/segments-normalization/normalization.d.ts.map +1 -1
- package/dist/types/src/testing/testing.d.ts +1 -1
- package/dist/types/src/testing/testing.d.ts.map +1 -1
- package/dist/types/src/transcriber/transcription-manager.d.ts +3 -7
- package/dist/types/src/transcriber/transcription-manager.d.ts.map +1 -1
- package/dist/types/src/types/Transcript.d.ts +30 -0
- package/dist/types/src/types/Transcript.d.ts.map +1 -0
- package/dist/types/src/types/TranscriptAction.d.ts +23 -0
- package/dist/types/src/types/TranscriptAction.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -1
- package/dist/types/src/types/index.d.ts.map +1 -1
- package/dist/types/src/types/types.d.ts +0 -26
- package/dist/types/src/types/types.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +61 -62
- package/src/TranscriptionPlugin.tsx +57 -53
- package/src/capabilities/blueprint-definition.ts +31 -0
- package/src/capabilities/capabilities.ts +3 -3
- package/src/capabilities/index.ts +1 -0
- package/src/capabilities/intent-resolver.ts +4 -10
- package/src/capabilities/react-surface.tsx +2 -2
- package/src/components/Transcript/Transcript.stories.tsx +32 -30
- package/src/components/Transcript/Transcript.tsx +17 -25
- package/src/components/Transcript/deprecated/OldTranscript.tsx +7 -7
- package/src/components/Transcript/transcript-extension.ts +2 -39
- package/src/components/TranscriptContainer.tsx +6 -6
- package/src/components/stories/FileTranscription.stories.tsx +42 -30
- package/src/components/stories/KeyWordRecognition.stories.tsx +16 -9
- package/src/components/stories/MicrophoneTranscription.stories.tsx +36 -32
- package/src/components/stories/TranscriptionStory.tsx +10 -6
- package/src/functions/index.ts +6 -0
- package/src/functions/open.ts +39 -0
- package/src/functions/summarize.ts +103 -0
- package/src/hooks/useAudioFile.ts +49 -53
- package/src/meta.ts +1 -3
- package/src/segments-normalization/normalization.test.ts +1 -1
- package/src/segments-normalization/normalization.ts +1 -1
- package/src/testing/testing.ts +5 -5
- package/src/transcriber/transcription-manager.ts +17 -38
- package/src/types/{schema.ts → Transcript.ts} +12 -9
- package/src/types/TranscriptAction.ts +24 -0
- package/src/types/index.ts +2 -1
- package/src/types/types.ts +0 -24
- package/dist/lib/browser/TranscriptContainer-FH7VAWYA.mjs +0 -11
- package/dist/lib/browser/chunk-5WH45KBY.mjs.map +0 -7
- package/dist/lib/browser/chunk-BJWYA2BU.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.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/react-surface-4MEJMKYQ.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-TM2ASOZA.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-XMUCZBP3.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-Y7PCJ34K.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/react-surface-EZUPNHUC.mjs.map +0 -7
- package/dist/types/src/types/schema.d.ts +0 -41
- package/dist/types/src/types/schema.d.ts.map +0 -1
- /package/dist/lib/browser/{TranscriptContainer-FH7VAWYA.mjs.map → TranscriptContainer-QN5WUMWJ.mjs.map} +0 -0
- /package/dist/lib/browser/{chunk-UKUSJTQW.mjs.map → chunk-77NWYLC6.mjs.map} +0 -0
- /package/dist/lib/node-esm/{TranscriptContainer-GEUOOYHX.mjs.map → TranscriptContainer-WCUWVVSD.mjs.map} +0 -0
- /package/dist/lib/node-esm/{chunk-PHP7MCAY.mjs.map → chunk-N5Z4SKPH.mjs.map} +0 -0
|
@@ -6,27 +6,27 @@ import React from 'react';
|
|
|
6
6
|
|
|
7
7
|
import { type Space } from '@dxos/react-client/echo';
|
|
8
8
|
import { type Identity } from '@dxos/react-client/halo';
|
|
9
|
-
import {
|
|
9
|
+
import { type ThemedClassName, useThemeContext } from '@dxos/react-ui';
|
|
10
10
|
import {
|
|
11
|
+
autoScroll,
|
|
11
12
|
createBasicExtensions,
|
|
12
13
|
createMarkdownExtensions,
|
|
13
|
-
createRenderer,
|
|
14
14
|
createThemeExtensions,
|
|
15
15
|
decorateMarkdown,
|
|
16
|
-
editorWidth,
|
|
17
16
|
preview,
|
|
18
17
|
useTextEditor,
|
|
19
18
|
} from '@dxos/react-ui-editor';
|
|
20
19
|
import { mx } from '@dxos/react-ui-theme';
|
|
21
20
|
import { type DataType } from '@dxos/schema';
|
|
22
|
-
import {
|
|
21
|
+
import { isTruthy } from '@dxos/util';
|
|
23
22
|
|
|
24
23
|
import { type SerializationModel } from '../../model';
|
|
25
|
-
import { type
|
|
24
|
+
import { type Transcript } from '../../types';
|
|
26
25
|
|
|
27
26
|
import { transcript } from './transcript-extension';
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
// TODO(thure): Move this?
|
|
29
|
+
export const renderByline =
|
|
30
30
|
(identities: Identity[]) =>
|
|
31
31
|
(message: DataType.Message, index: number, debug = false): string[] => {
|
|
32
32
|
if (message.sender.role === 'assistant') {
|
|
@@ -45,17 +45,18 @@ export const renderMarkdown =
|
|
|
45
45
|
message.sender.identityDid;
|
|
46
46
|
const blocks = message.blocks.filter((block) => block._tag === 'transcript');
|
|
47
47
|
return [
|
|
48
|
+
// TODO(thure): Use an XML tag with the bits needed here.
|
|
48
49
|
`###### ${name}` + (debug ? ` [${index}]:${message.id}` : ''),
|
|
49
50
|
blocks.map((block) => block.text.trim()).join(' '),
|
|
50
51
|
'',
|
|
51
52
|
];
|
|
52
53
|
};
|
|
53
54
|
|
|
54
|
-
export type
|
|
55
|
-
transcript?: TranscriptType;
|
|
55
|
+
export type TranscriptViewProps = ThemedClassName<{
|
|
56
56
|
space?: Space;
|
|
57
|
+
transcript?: Transcript.Transcript;
|
|
57
58
|
model: SerializationModel<DataType.Message>;
|
|
58
|
-
// TODO(
|
|
59
|
+
// TODO(burdon): Are these still in use?
|
|
59
60
|
attendableId?: string;
|
|
60
61
|
ignoreAttention?: boolean;
|
|
61
62
|
}>;
|
|
@@ -63,39 +64,30 @@ export type TranscriptProps = ThemedClassName<{
|
|
|
63
64
|
/**
|
|
64
65
|
* Transcript component implemented using the editor.
|
|
65
66
|
*/
|
|
66
|
-
export const
|
|
67
|
-
classNames,
|
|
68
|
-
transcript: object,
|
|
69
|
-
space,
|
|
70
|
-
model,
|
|
71
|
-
attendableId,
|
|
72
|
-
ignoreAttention,
|
|
73
|
-
}: TranscriptProps) => {
|
|
67
|
+
export const TranscriptView = ({ classNames, space, transcript: object, model }: TranscriptViewProps) => {
|
|
74
68
|
const { themeMode } = useThemeContext();
|
|
75
69
|
const { parentRef } = useTextEditor(() => {
|
|
76
70
|
return {
|
|
77
71
|
extensions: [
|
|
78
72
|
createBasicExtensions({ readOnly: true, lineWrapping: true, search: true }),
|
|
79
|
-
createMarkdownExtensions(
|
|
73
|
+
createMarkdownExtensions(),
|
|
80
74
|
createThemeExtensions({ themeMode }),
|
|
81
75
|
decorateMarkdown(),
|
|
82
|
-
|
|
76
|
+
preview(),
|
|
83
77
|
transcript({
|
|
84
78
|
model,
|
|
85
79
|
started: object?.started ? new Date(object.started) : undefined,
|
|
86
|
-
renderButton: createRenderer(({ onClick }) => (
|
|
87
|
-
<IconButton icon='ph--arrow-line-down--regular' iconOnly label='Scroll to bottom' onClick={onClick} />
|
|
88
|
-
)),
|
|
89
80
|
}),
|
|
90
|
-
|
|
81
|
+
autoScroll(),
|
|
82
|
+
].filter(isTruthy),
|
|
91
83
|
};
|
|
92
84
|
}, [space, model]);
|
|
93
85
|
|
|
94
86
|
return (
|
|
95
87
|
<div
|
|
96
88
|
ref={parentRef}
|
|
97
|
-
className={mx('flex grow overflow-hidden',
|
|
98
|
-
data-popover-collision-boundary={true}
|
|
89
|
+
className={mx('flex grow overflow-hidden container-max-width', classNames)}
|
|
90
|
+
data-popover-collision-boundary={true /* TODO(thure): Make this a constant and document it. */}
|
|
99
91
|
/>
|
|
100
92
|
);
|
|
101
93
|
};
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import { intervalToDuration } from 'date-fns/intervalToDuration';
|
|
6
|
-
import
|
|
6
|
+
import * as Schema from 'effect/Schema';
|
|
7
7
|
import { yieldOrContinue } from 'main-thread-scheduling';
|
|
8
8
|
import React, { type FC, type WheelEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
9
9
|
import { type OnResizeCallback, useResizeDetector } from 'react-resize-detector';
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from '@dxos/react-ui-grid';
|
|
22
22
|
import { mx } from '@dxos/react-ui-theme';
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import { meta } from '../../../meta';
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
27
|
* Transcription fragment.
|
|
@@ -115,7 +115,7 @@ const measureRows = async (
|
|
|
115
115
|
return result;
|
|
116
116
|
};
|
|
117
117
|
|
|
118
|
-
export type
|
|
118
|
+
export type TranscriptViewProps = ThemedClassName<{
|
|
119
119
|
blocks?: TranscriptBlock[];
|
|
120
120
|
attendableId?: string;
|
|
121
121
|
ignoreAttention?: boolean;
|
|
@@ -124,8 +124,8 @@ export type TranscriptProps = ThemedClassName<{
|
|
|
124
124
|
/**
|
|
125
125
|
* @@deprecated
|
|
126
126
|
*/
|
|
127
|
-
export const Transcript: FC<
|
|
128
|
-
const { t } = useTranslation(
|
|
127
|
+
export const Transcript: FC<TranscriptViewProps> = ({ classNames, blocks, attendableId, ignoreAttention }) => {
|
|
128
|
+
const { t } = useTranslation(meta.id);
|
|
129
129
|
const [dxGrid, setDxGrid] = useState<DxGridElement | null>(null);
|
|
130
130
|
const [rows, setRows] = useState<DxGridAxisMeta | undefined>(undefined);
|
|
131
131
|
const [columns, setColumns] = useState<DxGridAxisMeta | undefined>(undefined);
|
|
@@ -144,7 +144,7 @@ export const Transcript: FC<TranscriptProps> = ({ classNames, blocks, attendable
|
|
|
144
144
|
[hasAttention, ignoreAttention],
|
|
145
145
|
);
|
|
146
146
|
|
|
147
|
-
const abortControllerRef = useRef<AbortController>();
|
|
147
|
+
const abortControllerRef = useRef<AbortController>(null);
|
|
148
148
|
|
|
149
149
|
const handleResize = useCallback(
|
|
150
150
|
async ({ entry }: { entry: { target: HTMLDivElement } | null }) => {
|
|
@@ -242,7 +242,7 @@ export const Transcript: FC<TranscriptProps> = ({ classNames, blocks, attendable
|
|
|
242
242
|
ref={setDxGrid}
|
|
243
243
|
/>
|
|
244
244
|
</Grid.Root>
|
|
245
|
-
<div role='none' {...{ inert:
|
|
245
|
+
<div role='none' {...{ inert: true }} aria-hidden className={measureClasses} ref={measureRef} />
|
|
246
246
|
<IconButton
|
|
247
247
|
icon='ph--arrow-line-down--regular'
|
|
248
248
|
iconOnly
|
|
@@ -8,7 +8,6 @@ import { format } from 'date-fns/format';
|
|
|
8
8
|
import { intervalToDuration } from 'date-fns/intervalToDuration';
|
|
9
9
|
|
|
10
10
|
import { type CleanupFn, addEventListener, combine } from '@dxos/async';
|
|
11
|
-
import { type RenderCallback } from '@dxos/react-ui-editor';
|
|
12
11
|
import { type DataType } from '@dxos/schema';
|
|
13
12
|
|
|
14
13
|
import { DocumentAdapter, type SerializationModel } from '../../model';
|
|
@@ -19,13 +18,12 @@ import { DocumentAdapter, type SerializationModel } from '../../model';
|
|
|
19
18
|
export type TranscriptOptions = {
|
|
20
19
|
model: SerializationModel<DataType.Message>;
|
|
21
20
|
started?: Date;
|
|
22
|
-
renderButton?: RenderCallback<{ onClick: () => void }>;
|
|
23
21
|
};
|
|
24
22
|
|
|
25
23
|
/**
|
|
26
24
|
* Scrolling transcript with timestamps.
|
|
27
25
|
*/
|
|
28
|
-
export const transcript = ({ model, started
|
|
26
|
+
export const transcript = ({ model, started }: TranscriptOptions): Extension => {
|
|
29
27
|
return [
|
|
30
28
|
// Show timestamps in the gutter.
|
|
31
29
|
gutter({
|
|
@@ -90,22 +88,6 @@ export const transcript = ({ model, started, renderButton }: TranscriptOptions):
|
|
|
90
88
|
});
|
|
91
89
|
};
|
|
92
90
|
|
|
93
|
-
// Scroll button.
|
|
94
|
-
if (renderButton) {
|
|
95
|
-
this._controls = document.createElement('div');
|
|
96
|
-
this._controls.classList.add('cm-controls', 'transition-opacity', 'duration-300', 'opacity-0');
|
|
97
|
-
view.dom.appendChild(this._controls);
|
|
98
|
-
renderButton(
|
|
99
|
-
this._controls,
|
|
100
|
-
{
|
|
101
|
-
onClick: () => {
|
|
102
|
-
scrollToBottom(false);
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
view,
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
91
|
// Event listeners.
|
|
110
92
|
this._cleanup = combine(
|
|
111
93
|
addEventListener(view.scrollDOM, 'scroll', () => {
|
|
@@ -131,7 +113,7 @@ export const transcript = ({ model, started, renderButton }: TranscriptOptions):
|
|
|
131
113
|
);
|
|
132
114
|
}
|
|
133
115
|
|
|
134
|
-
update(
|
|
116
|
+
update(_update: ViewUpdate) {
|
|
135
117
|
// Initial sync.
|
|
136
118
|
if (!this._initialized) {
|
|
137
119
|
this._initialized = true;
|
|
@@ -149,25 +131,6 @@ export const transcript = ({ model, started, renderButton }: TranscriptOptions):
|
|
|
149
131
|
),
|
|
150
132
|
|
|
151
133
|
EditorView.theme({
|
|
152
|
-
'.cm-scroller': {
|
|
153
|
-
overflowY: 'scroll',
|
|
154
|
-
},
|
|
155
|
-
'.cm-hide-scrollbar': {
|
|
156
|
-
scrollbarWidth: 'none',
|
|
157
|
-
'-ms-overflow-style': 'none',
|
|
158
|
-
},
|
|
159
|
-
'.cm-hide-scrollbar::-webkit-scrollbar': {
|
|
160
|
-
display: 'none',
|
|
161
|
-
},
|
|
162
|
-
'.cm-controls': {
|
|
163
|
-
position: 'absolute',
|
|
164
|
-
bottom: '0.5rem',
|
|
165
|
-
right: '0.5rem',
|
|
166
|
-
zIndex: 1000,
|
|
167
|
-
},
|
|
168
|
-
'.cm-line': {
|
|
169
|
-
paddingRight: '1rem',
|
|
170
|
-
},
|
|
171
134
|
'.cm-timestamp-gutter': {
|
|
172
135
|
width: '6rem',
|
|
173
136
|
paddingRight: '1rem',
|
|
@@ -10,13 +10,13 @@ import { StackItem } from '@dxos/react-ui-stack';
|
|
|
10
10
|
import { type DataType } from '@dxos/schema';
|
|
11
11
|
|
|
12
12
|
import { useQueueModelAdapter } from '../hooks';
|
|
13
|
-
import { type
|
|
13
|
+
import { type Transcript } from '../types';
|
|
14
14
|
|
|
15
|
-
import {
|
|
15
|
+
import { TranscriptView, renderByline } from './Transcript';
|
|
16
16
|
|
|
17
17
|
export type TranscriptionContainerProps = {
|
|
18
18
|
role: string;
|
|
19
|
-
transcript:
|
|
19
|
+
transcript: Transcript.Transcript;
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export const TranscriptionContainer = ({ transcript }: TranscriptionContainerProps) => {
|
|
@@ -24,11 +24,11 @@ export const TranscriptionContainer = ({ transcript }: TranscriptionContainerPro
|
|
|
24
24
|
const space = getSpace(transcript);
|
|
25
25
|
const members = useMembers(space?.key).map((member) => member.identity);
|
|
26
26
|
const queue = useQueue<DataType.Message>(transcript.queue.dxn, { pollInterval: 1_000 });
|
|
27
|
-
const model = useQueueModelAdapter(
|
|
27
|
+
const model = useQueueModelAdapter(renderByline(members), queue);
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
|
-
<StackItem.Content
|
|
31
|
-
<
|
|
30
|
+
<StackItem.Content>
|
|
31
|
+
<TranscriptView attendableId={attendableId} space={space} model={model} transcript={transcript} />
|
|
32
32
|
</StackItem.Content>
|
|
33
33
|
);
|
|
34
34
|
};
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
9
7
|
|
|
@@ -12,8 +10,8 @@ import { withPluginManager } from '@dxos/app-framework/testing';
|
|
|
12
10
|
import { scheduleTask } from '@dxos/async';
|
|
13
11
|
import { Context } from '@dxos/context';
|
|
14
12
|
import { Obj } from '@dxos/echo';
|
|
13
|
+
import { createQueueDXN } from '@dxos/echo/internal';
|
|
15
14
|
import { MemoryQueue } from '@dxos/echo-db';
|
|
16
|
-
import { createQueueDXN } from '@dxos/echo-schema';
|
|
17
15
|
import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
|
|
18
16
|
import { log } from '@dxos/log';
|
|
19
17
|
import { ClientPlugin } from '@dxos/plugin-client';
|
|
@@ -21,17 +19,17 @@ import { PreviewPlugin } from '@dxos/plugin-preview';
|
|
|
21
19
|
import { SpacePlugin } from '@dxos/plugin-space';
|
|
22
20
|
import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
|
|
23
21
|
import { ThemePlugin } from '@dxos/plugin-theme';
|
|
22
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
24
23
|
import { defaultTx } from '@dxos/react-ui-theme';
|
|
25
24
|
import { DataType } from '@dxos/schema';
|
|
26
25
|
import { Testing, seedTestData } from '@dxos/schema/testing';
|
|
27
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
28
26
|
|
|
29
27
|
import { useAudioFile, useQueueModelAdapter, useTranscriber } from '../../hooks';
|
|
30
28
|
import { MessageNormalizer, getActorId } from '../../segments-normalization';
|
|
31
29
|
import { TestItem } from '../../testing';
|
|
32
30
|
import { type MediaStreamRecorderParams, type TranscriberParams } from '../../transcriber';
|
|
33
31
|
import { TranscriptionPlugin } from '../../TranscriptionPlugin';
|
|
34
|
-
import {
|
|
32
|
+
import { renderByline } from '../Transcript';
|
|
35
33
|
|
|
36
34
|
import { TranscriptionStory } from './TranscriptionStory';
|
|
37
35
|
import { useIsSpeaking } from './useIsSpeaking';
|
|
@@ -68,7 +66,6 @@ const AudioFile = ({
|
|
|
68
66
|
|
|
69
67
|
useEffect(() => {
|
|
70
68
|
if (!audio) {
|
|
71
|
-
log.warn('no audio');
|
|
72
69
|
return;
|
|
73
70
|
}
|
|
74
71
|
|
|
@@ -84,7 +81,7 @@ const AudioFile = ({
|
|
|
84
81
|
const queueDxn = useMemo(() => createQueueDXN(), []);
|
|
85
82
|
const queue = useMemo(() => new MemoryQueue<DataType.Message>(queueDxn), [queueDxn]);
|
|
86
83
|
|
|
87
|
-
const model = useQueueModelAdapter(
|
|
84
|
+
const model = useQueueModelAdapter(renderByline([]), queue);
|
|
88
85
|
const handleSegments = useCallback<TranscriberParams['onSegments']>(
|
|
89
86
|
async (blocks) => {
|
|
90
87
|
void queue?.append([
|
|
@@ -147,10 +144,10 @@ const AudioFile = ({
|
|
|
147
144
|
}, [normalizer]);
|
|
148
145
|
|
|
149
146
|
const manageChunkRecording = () => {
|
|
150
|
-
if (running && isSpeaking) {
|
|
147
|
+
if (running && isSpeaking && transcriber) {
|
|
151
148
|
log.info('starting transcription');
|
|
152
149
|
transcriber?.startChunksRecording();
|
|
153
|
-
} else if (!isSpeaking || !running) {
|
|
150
|
+
} else if ((!isSpeaking || !running) && transcriber) {
|
|
154
151
|
log.info('stopping transcription');
|
|
155
152
|
transcriber?.stopChunksRecording();
|
|
156
153
|
}
|
|
@@ -176,16 +173,23 @@ const AudioFile = ({
|
|
|
176
173
|
manageChunkRecording();
|
|
177
174
|
}, [isSpeaking, stream]);
|
|
178
175
|
|
|
179
|
-
return
|
|
176
|
+
return (
|
|
177
|
+
<TranscriptionStory
|
|
178
|
+
disabled={!stream}
|
|
179
|
+
model={model}
|
|
180
|
+
running={running}
|
|
181
|
+
onRunningChange={setRunning}
|
|
182
|
+
audioRef={ref}
|
|
183
|
+
/>
|
|
184
|
+
);
|
|
180
185
|
};
|
|
181
186
|
|
|
182
|
-
const meta
|
|
187
|
+
const meta = {
|
|
183
188
|
title: 'plugins/plugin-transcription/FileTranscription',
|
|
184
189
|
decorators: [
|
|
190
|
+
withTheme,
|
|
185
191
|
withPluginManager({
|
|
186
192
|
plugins: [
|
|
187
|
-
ThemePlugin({ tx: defaultTx }),
|
|
188
|
-
StorybookLayoutPlugin(),
|
|
189
193
|
ClientPlugin({
|
|
190
194
|
types: [TestItem, DataType.Person, DataType.Organization, Testing.DocumentType],
|
|
191
195
|
onClientInitialized: async ({ client }) => {
|
|
@@ -195,21 +199,28 @@ const meta: Meta<typeof AudioFile> = {
|
|
|
195
199
|
await seedTestData(client.spaces.default);
|
|
196
200
|
},
|
|
197
201
|
}),
|
|
198
|
-
SpacePlugin(),
|
|
202
|
+
SpacePlugin({}),
|
|
203
|
+
IntentPlugin(),
|
|
204
|
+
|
|
205
|
+
// UI
|
|
206
|
+
ThemePlugin({ tx: defaultTx }),
|
|
199
207
|
SettingsPlugin(),
|
|
200
208
|
PreviewPlugin(),
|
|
201
|
-
IntentPlugin(),
|
|
202
209
|
TranscriptionPlugin(),
|
|
210
|
+
StorybookLayoutPlugin({}),
|
|
203
211
|
],
|
|
204
212
|
fireEvents: [Events.SetupAppGraph],
|
|
205
213
|
}),
|
|
206
|
-
withTheme,
|
|
207
|
-
withLayout({ fullscreen: true, classNames: 'justify-center' }),
|
|
208
214
|
],
|
|
209
|
-
|
|
215
|
+
parameters: {
|
|
216
|
+
layout: 'column',
|
|
217
|
+
},
|
|
218
|
+
} satisfies Meta;
|
|
210
219
|
|
|
211
220
|
export default meta;
|
|
212
221
|
|
|
222
|
+
type Story = StoryObj<typeof meta>;
|
|
223
|
+
|
|
213
224
|
const TRANSCRIBER_CONFIG = {
|
|
214
225
|
transcribeAfterChunksAmount: 100,
|
|
215
226
|
prefixBufferChunksAmount: 50,
|
|
@@ -232,15 +243,16 @@ export const Default: StoryObj<typeof AudioFile> = {
|
|
|
232
243
|
},
|
|
233
244
|
};
|
|
234
245
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
}
|
|
246
|
+
// TODO(mykola): Fix sentence normalization.
|
|
247
|
+
// export const WithSentenceNormalization: StoryObj<typeof AudioFile> = {
|
|
248
|
+
// render: AudioFile,
|
|
249
|
+
// args: {
|
|
250
|
+
// detectSpeaking: true,
|
|
251
|
+
// normalizeSentences: true,
|
|
252
|
+
// // https://learnenglish.britishcouncil.org/general-english/audio-zone/living-london
|
|
253
|
+
// audioUrl: 'https://dxos.network/audio-london.m4a',
|
|
254
|
+
// // textUrl: 'https://dxos.network/audio-london.txt',
|
|
255
|
+
// transcriberConfig: TRANSCRIBER_CONFIG,
|
|
256
|
+
// recorderConfig: RECORDER_CONFIG,
|
|
257
|
+
// },
|
|
258
|
+
// };
|
|
@@ -2,22 +2,24 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
9
7
|
|
|
10
8
|
import { log } from '@dxos/log';
|
|
11
9
|
import { Toolbar } from '@dxos/react-ui';
|
|
10
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
12
11
|
import { mx } from '@dxos/react-ui-theme';
|
|
13
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
14
12
|
|
|
15
13
|
type Word = {
|
|
16
14
|
text: string;
|
|
17
15
|
matched: boolean;
|
|
18
16
|
};
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
type StoryProps = {
|
|
19
|
+
keywords: string[];
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const DefaultStory = ({ keywords }: StoryProps) => {
|
|
21
23
|
const [running, setRunning] = useState(false);
|
|
22
24
|
const [matchingWords, setMatchingWords] = useState<Word[]>(keywords.map((word) => ({ text: word, matched: false })));
|
|
23
25
|
|
|
@@ -113,15 +115,20 @@ const SpeechRecognition = ({ keywords }: { keywords: string[] }) => {
|
|
|
113
115
|
);
|
|
114
116
|
};
|
|
115
117
|
|
|
116
|
-
const meta
|
|
118
|
+
const meta = {
|
|
117
119
|
title: 'plugins/plugin-transcription/KeyWordDetection',
|
|
118
|
-
|
|
119
|
-
|
|
120
|
+
render: DefaultStory,
|
|
121
|
+
decorators: [withTheme],
|
|
122
|
+
parameters: {
|
|
123
|
+
layout: 'column',
|
|
124
|
+
},
|
|
125
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
120
126
|
|
|
121
127
|
export default meta;
|
|
122
128
|
|
|
123
|
-
|
|
124
|
-
|
|
129
|
+
type Story = StoryObj<typeof meta>;
|
|
130
|
+
|
|
131
|
+
export const SpeechRecognitionAPI: Story = {
|
|
125
132
|
args: {
|
|
126
133
|
keywords: ['kai', 'computer', 'hello'],
|
|
127
134
|
},
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
// Copyright 2025 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import '@dxos-theme';
|
|
6
|
-
|
|
7
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
8
6
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
9
7
|
|
|
@@ -11,14 +9,14 @@ import { Events, IntentPlugin, SettingsPlugin } from '@dxos/app-framework';
|
|
|
11
9
|
import { withPluginManager } from '@dxos/app-framework/testing';
|
|
12
10
|
import {
|
|
13
11
|
type ExtractionFunction,
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
extractionAnthropicFunction,
|
|
13
|
+
extractionNerFunction,
|
|
16
14
|
getNer,
|
|
17
15
|
processTranscriptMessage,
|
|
18
16
|
} from '@dxos/assistant/extraction';
|
|
19
17
|
import { Filter, Obj, type Type } from '@dxos/echo';
|
|
18
|
+
import { createQueueDXN } from '@dxos/echo/internal';
|
|
20
19
|
import { MemoryQueue } from '@dxos/echo-db';
|
|
21
|
-
import { createQueueDXN } from '@dxos/echo-schema';
|
|
22
20
|
import { FunctionExecutor, ServiceContainer } from '@dxos/functions';
|
|
23
21
|
import { invariant } from '@dxos/invariant';
|
|
24
22
|
import { log } from '@dxos/log';
|
|
@@ -28,16 +26,16 @@ import { SpacePlugin } from '@dxos/plugin-space';
|
|
|
28
26
|
import { StorybookLayoutPlugin } from '@dxos/plugin-storybook-layout';
|
|
29
27
|
import { ThemePlugin } from '@dxos/plugin-theme';
|
|
30
28
|
import { IndexKind, useSpace } from '@dxos/react-client/echo';
|
|
29
|
+
import { withTheme } from '@dxos/react-ui/testing';
|
|
31
30
|
import { defaultTx } from '@dxos/react-ui-theme';
|
|
32
31
|
import { DataType } from '@dxos/schema';
|
|
33
32
|
import { Testing, seedTestData } from '@dxos/schema/testing';
|
|
34
|
-
import { withLayout, withTheme } from '@dxos/storybook-utils';
|
|
35
33
|
|
|
36
34
|
import { useAudioTrack, useQueueModelAdapter, useTranscriber } from '../../hooks';
|
|
37
35
|
import { TestItem } from '../../testing';
|
|
38
36
|
import { type MediaStreamRecorderParams, type TranscriberParams } from '../../transcriber';
|
|
39
37
|
import { TranscriptionPlugin } from '../../TranscriptionPlugin';
|
|
40
|
-
import {
|
|
38
|
+
import { renderByline } from '../Transcript';
|
|
41
39
|
|
|
42
40
|
import { TranscriptionStory } from './TranscriptionStory';
|
|
43
41
|
import { useIsSpeaking } from './useIsSpeaking';
|
|
@@ -78,7 +76,7 @@ const DefaultStory = ({
|
|
|
78
76
|
// TODO(dmaretskyi): Use space.queues.create() instead.
|
|
79
77
|
const queueDxn = useMemo(() => createQueueDXN(), []);
|
|
80
78
|
const queue = useMemo(() => new MemoryQueue<DataType.Message>(queueDxn), [queueDxn]);
|
|
81
|
-
const model = useQueueModelAdapter(
|
|
79
|
+
const model = useQueueModelAdapter(renderByline([]), queue);
|
|
82
80
|
const space = useSpace();
|
|
83
81
|
|
|
84
82
|
useEffect(() => {
|
|
@@ -101,9 +99,9 @@ const DefaultStory = ({
|
|
|
101
99
|
if (entityExtraction === 'ner') {
|
|
102
100
|
// Init model loading. Takes time.
|
|
103
101
|
void getNer();
|
|
104
|
-
extractionFunction =
|
|
102
|
+
extractionFunction = extractionNerFunction;
|
|
105
103
|
} else if (entityExtraction === 'llm') {
|
|
106
|
-
extractionFunction =
|
|
104
|
+
extractionFunction = extractionAnthropicFunction;
|
|
107
105
|
objects = space.db
|
|
108
106
|
.query(
|
|
109
107
|
Filter.or(
|
|
@@ -193,14 +191,13 @@ const DefaultStory = ({
|
|
|
193
191
|
return <TranscriptionStory model={model} running={running} onRunningChange={setRunning} />;
|
|
194
192
|
};
|
|
195
193
|
|
|
196
|
-
const meta
|
|
194
|
+
const meta = {
|
|
197
195
|
title: 'plugins/plugin-transcription/MicrophoneTranscription',
|
|
198
196
|
render: DefaultStory,
|
|
199
197
|
decorators: [
|
|
198
|
+
withTheme,
|
|
200
199
|
withPluginManager({
|
|
201
200
|
plugins: [
|
|
202
|
-
ThemePlugin({ tx: defaultTx }),
|
|
203
|
-
StorybookLayoutPlugin(),
|
|
204
201
|
ClientPlugin({
|
|
205
202
|
types: [TestItem, DataType.Person, DataType.Organization, Testing.DocumentType],
|
|
206
203
|
onClientInitialized: async ({ client }) => {
|
|
@@ -223,22 +220,27 @@ const meta: Meta<typeof DefaultStory> = {
|
|
|
223
220
|
await seedTestData(client.spaces.default);
|
|
224
221
|
},
|
|
225
222
|
}),
|
|
226
|
-
SpacePlugin(),
|
|
223
|
+
SpacePlugin({}),
|
|
224
|
+
IntentPlugin(),
|
|
227
225
|
SettingsPlugin(),
|
|
226
|
+
|
|
227
|
+
// UI
|
|
228
|
+
ThemePlugin({ tx: defaultTx }),
|
|
228
229
|
PreviewPlugin(),
|
|
229
|
-
IntentPlugin(),
|
|
230
230
|
TranscriptionPlugin(),
|
|
231
|
+
StorybookLayoutPlugin({}),
|
|
231
232
|
],
|
|
232
233
|
fireEvents: [Events.SetupAppGraph],
|
|
233
234
|
}),
|
|
234
|
-
withTheme,
|
|
235
|
-
withLayout({ fullscreen: true, classNames: 'justify-center' }),
|
|
236
235
|
],
|
|
237
|
-
|
|
236
|
+
parameters: {
|
|
237
|
+
layout: 'column',
|
|
238
|
+
},
|
|
239
|
+
} satisfies Meta<typeof DefaultStory>;
|
|
238
240
|
|
|
239
241
|
export default meta;
|
|
240
242
|
|
|
241
|
-
type Story = StoryObj<typeof
|
|
243
|
+
type Story = StoryObj<typeof meta>;
|
|
242
244
|
|
|
243
245
|
export const Default: Story = {
|
|
244
246
|
args: {
|
|
@@ -254,19 +256,21 @@ export const Default: Story = {
|
|
|
254
256
|
},
|
|
255
257
|
};
|
|
256
258
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
}
|
|
259
|
+
// NOTE: We are running out of free quota on hugging face entity extraction.
|
|
260
|
+
// TODO(mykola): Fix hugging face quota issues.
|
|
261
|
+
// export const EntityExtraction: Story = {
|
|
262
|
+
// args: {
|
|
263
|
+
// detectSpeaking: true,
|
|
264
|
+
// entityExtraction: 'ner',
|
|
265
|
+
// transcriberConfig: TRANSCRIBER_CONFIG,
|
|
266
|
+
// recorderConfig: RECORDER_CONFIG,
|
|
267
|
+
// audioConstraints: {
|
|
268
|
+
// echoCancellation: true,
|
|
269
|
+
// noiseSuppression: true,
|
|
270
|
+
// autoGainControl: true,
|
|
271
|
+
// },
|
|
272
|
+
// },
|
|
273
|
+
// };
|
|
270
274
|
|
|
271
275
|
export const SpeechDetection: Story = {
|
|
272
276
|
args: {
|
|
@@ -12,14 +12,15 @@ import { ScrollContainer } from '@dxos/react-ui-components';
|
|
|
12
12
|
import { type DataType } from '@dxos/schema';
|
|
13
13
|
|
|
14
14
|
import { type SerializationModel } from '../../model';
|
|
15
|
-
import {
|
|
15
|
+
import { TranscriptView } from '../Transcript';
|
|
16
16
|
|
|
17
17
|
export const TranscriptionStory: FC<{
|
|
18
18
|
model: SerializationModel<DataType.Message>;
|
|
19
|
+
disabled?: boolean;
|
|
19
20
|
running: boolean;
|
|
20
21
|
onRunningChange: Dispatch<SetStateAction<boolean>>;
|
|
21
|
-
audioRef?: RefObject<HTMLAudioElement>;
|
|
22
|
-
}> = ({ model, running, onRunningChange, audioRef }) => {
|
|
22
|
+
audioRef?: RefObject<HTMLAudioElement | null>;
|
|
23
|
+
}> = ({ model, running, onRunningChange, audioRef, disabled }) => {
|
|
23
24
|
const space = useSpace();
|
|
24
25
|
|
|
25
26
|
return (
|
|
@@ -28,14 +29,17 @@ export const TranscriptionStory: FC<{
|
|
|
28
29
|
<Toolbar.Root>
|
|
29
30
|
<IconButton
|
|
30
31
|
iconOnly
|
|
32
|
+
disabled={disabled}
|
|
31
33
|
icon={running ? 'ph--pause--regular' : 'ph--play--regular'}
|
|
32
34
|
label={running ? 'Pause' : 'Play'}
|
|
33
35
|
onClick={() => onRunningChange((running) => !running)}
|
|
34
36
|
/>
|
|
35
37
|
</Toolbar.Root>
|
|
36
|
-
<ScrollContainer>
|
|
37
|
-
<
|
|
38
|
-
|
|
38
|
+
<ScrollContainer.Root pin>
|
|
39
|
+
<ScrollContainer.Content>
|
|
40
|
+
<TranscriptView space={space} model={model} />
|
|
41
|
+
</ScrollContainer.Content>
|
|
42
|
+
</ScrollContainer.Root>
|
|
39
43
|
</div>
|
|
40
44
|
);
|
|
41
45
|
};
|