@dxos/plugin-transcription 0.10.0 → 0.11.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/dist/lib/TranscriptionPlugin.mjs +2 -0
- package/dist/lib/TranscriptionPlugin.node.mjs +11 -0
- package/dist/lib/TranscriptionPlugin.node.mjs.map +1 -0
- package/dist/lib/TranscriptionPlugin.workerd.mjs +11 -0
- package/dist/lib/TranscriptionPlugin.workerd.mjs.map +1 -0
- package/dist/lib/capabilities/node.mjs +9 -0
- package/dist/lib/capabilities/node.mjs.map +1 -0
- package/dist/lib/capabilities.mjs +18 -0
- package/dist/lib/capabilities.mjs.map +1 -0
- package/dist/lib/chunk-TranscriptionArticle.mjs +49 -0
- package/dist/lib/chunk-TranscriptionArticle.mjs.map +1 -0
- package/dist/lib/chunk-TranscriptionPlugin.mjs +39 -0
- package/dist/lib/chunk-TranscriptionPlugin.mjs.map +1 -0
- package/dist/lib/chunk-app-graph-builder.mjs +33 -0
- package/dist/lib/chunk-app-graph-builder.mjs.map +1 -0
- package/dist/lib/chunk-create.mjs +14 -0
- package/dist/lib/chunk-create.mjs.map +1 -0
- package/dist/lib/chunk-enrich-message.mjs +18 -0
- package/dist/lib/chunk-enrich-message.mjs.map +1 -0
- package/dist/lib/chunk-entity-lookup.mjs +26 -0
- package/dist/lib/chunk-entity-lookup.mjs.map +1 -0
- package/dist/lib/{neutral/markdown-extension-CCDXXY7E.mjs → chunk-markdown-extension.mjs} +7 -11
- package/dist/lib/chunk-markdown-extension.mjs.map +1 -0
- package/dist/lib/{neutral/chunk-5BVHY75B.mjs → chunk-meta.mjs} +20 -27
- package/dist/lib/chunk-meta.mjs.map +1 -0
- package/dist/lib/chunk-open.mjs +16 -0
- package/dist/lib/chunk-open.mjs.map +1 -0
- package/dist/lib/chunk-operation-handler.mjs +11 -0
- package/dist/lib/chunk-operation-handler.mjs.map +1 -0
- package/dist/lib/chunk-pipeline-status.mjs +17 -0
- package/dist/lib/chunk-pipeline-status.mjs.map +1 -0
- package/dist/lib/chunk-react-surface.mjs +21 -0
- package/dist/lib/chunk-react-surface.mjs.map +1 -0
- package/dist/lib/chunk-recording-session.mjs +13 -0
- package/dist/lib/chunk-recording-session.mjs.map +1 -0
- package/dist/lib/chunk-render-byline.mjs +15 -0
- package/dist/lib/chunk-render-byline.mjs.map +1 -0
- package/dist/lib/chunk-settings.mjs +26 -0
- package/dist/lib/chunk-settings.mjs.map +1 -0
- package/dist/lib/chunk-skill-definition.mjs +10 -0
- package/dist/lib/chunk-skill-definition.mjs.map +1 -0
- package/dist/lib/chunk-skills.mjs +21 -0
- package/dist/lib/chunk-skills.mjs.map +1 -0
- package/dist/lib/{neutral/summarize-LBUZTOTH.mjs → chunk-summarize.mjs} +25 -38
- package/dist/lib/chunk-summarize.mjs.map +1 -0
- package/dist/lib/chunk-text-content.mjs +28 -0
- package/dist/lib/chunk-text-content.mjs.map +1 -0
- package/dist/lib/chunk-transcriber.mjs +161 -0
- package/dist/lib/chunk-transcriber.mjs.map +1 -0
- package/dist/lib/chunk-transcription-driver.mjs +165 -0
- package/dist/lib/chunk-transcription-driver.mjs.map +1 -0
- package/dist/lib/chunk-types.mjs +141 -0
- package/dist/lib/chunk-types.mjs.map +1 -0
- package/dist/lib/components.mjs +108 -0
- package/dist/lib/components.mjs.map +1 -0
- package/dist/lib/containers.mjs +7 -0
- package/dist/lib/containers.mjs.map +1 -0
- package/dist/lib/hooks.mjs +87 -0
- package/dist/lib/hooks.mjs.map +1 -0
- package/dist/lib/index.mjs +4 -0
- package/dist/lib/meta.mjs +2 -0
- package/dist/lib/operations.mjs +7 -0
- package/dist/lib/operations.mjs.map +1 -0
- package/dist/lib/plugin.mjs +9 -0
- package/dist/lib/plugin.mjs.map +1 -0
- package/dist/lib/skills.mjs +2 -0
- package/dist/lib/testing.mjs +118 -0
- package/dist/lib/testing.mjs.map +1 -0
- package/dist/lib/translations.mjs +23 -0
- package/dist/lib/translations.mjs.map +1 -0
- package/dist/lib/types.mjs +2 -0
- package/dist/types/src/capabilities/app-graph-builder.d.ts +1 -1
- package/dist/types/src/capabilities/entity-lookup.d.ts +1 -1
- package/dist/types/src/capabilities/markdown-extension.d.ts +1 -1
- package/dist/types/src/capabilities/node.d.ts +6 -0
- package/dist/types/src/capabilities/node.d.ts.map +1 -0
- package/dist/types/src/capabilities/operation-handler.d.ts +1 -1
- package/dist/types/src/capabilities/pipeline-status.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts +1 -1
- package/dist/types/src/capabilities/react-surface.d.ts.map +1 -1
- package/dist/types/src/capabilities/recording-session.d.ts +1 -1
- package/dist/types/src/capabilities/settings.d.ts +1 -1
- package/dist/types/src/capabilities/text-content.d.ts +1 -1
- package/dist/types/src/capabilities/transcriber.d.ts +1 -1
- package/dist/types/src/capabilities/transcriber.d.ts.map +1 -1
- package/dist/types/src/capabilities/transcription-driver.d.ts +1 -1
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts +4 -1
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.d.ts.map +1 -1
- package/dist/types/src/containers/TranscriptionArticle/TranscriptionArticle.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useTranscriptionRecording.d.ts.map +1 -1
- package/dist/types/src/normalization/message-normalizer.d.ts +4 -4
- package/dist/types/src/normalization/message-normalizer.d.ts.map +1 -1
- package/dist/types/src/normalization/normalization.d.ts +97 -87
- 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/stories/Pipeline.stories.d.ts.map +1 -1
- package/dist/types/src/stories/Transcription.stories.d.ts.map +1 -1
- package/dist/types/src/transcription-manager.d.ts +1 -1
- package/dist/types/src/transcription-manager.d.ts.map +1 -1
- package/dist/types/src/types/TranscriptOperation.d.ts +97 -87
- package/dist/types/src/types/TranscriptOperation.d.ts.map +1 -1
- package/dist/types/src/types/TranscriptionCapabilities.d.ts +2 -2
- package/dist/types/src/types/TranscriptionCapabilities.d.ts.map +1 -1
- package/dist/types/src/util/index.d.ts +1 -0
- package/dist/types/src/util/index.d.ts.map +1 -1
- package/dist/types/src/util/render-byline.d.ts +11 -0
- package/dist/types/src/util/render-byline.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dx.config.ts +1 -1
- package/package.json +78 -70
- package/src/capabilities/entity-lookup.ts +1 -1
- package/src/capabilities/node.ts +17 -0
- package/src/capabilities/pipeline-status.ts +1 -1
- package/src/capabilities/{react-surface.tsx → react-surface.ts} +2 -4
- package/src/capabilities/recording-session.ts +1 -1
- package/src/capabilities/text-content.ts +9 -4
- package/src/capabilities/transcriber.ts +3 -1
- package/src/capabilities/transcription-driver.tsx +1 -1
- package/src/containers/TranscriptionArticle/TranscriptionArticle.stories.tsx +2 -1
- package/src/containers/TranscriptionArticle/TranscriptionArticle.tsx +8 -3
- package/src/hooks/useTranscriptionRecording.ts +7 -8
- package/src/normalization/message-normalizer.ts +10 -7
- package/src/normalization/normalization.test.ts +41 -44
- package/src/operations/open.ts +1 -1
- package/src/stories/Pipeline.stories.tsx +15 -14
- package/src/stories/Transcription.stories.tsx +3 -8
- package/src/transcription-manager.ts +2 -2
- package/src/types/TranscriptionCapabilities.ts +2 -2
- package/src/util/index.ts +1 -0
- package/src/util/render-byline.ts +40 -0
- package/dist/lib/neutral/TranscriptionArticle-FEWCWG4A.mjs +0 -51
- package/dist/lib/neutral/TranscriptionArticle-FEWCWG4A.mjs.map +0 -7
- package/dist/lib/neutral/TranscriptionPlugin.mjs +0 -69
- package/dist/lib/neutral/TranscriptionPlugin.mjs.map +0 -7
- package/dist/lib/neutral/TranscriptionPlugin.node.mjs +0 -25
- package/dist/lib/neutral/TranscriptionPlugin.node.mjs.map +0 -7
- package/dist/lib/neutral/TranscriptionPlugin.workerd.mjs +0 -21
- package/dist/lib/neutral/TranscriptionPlugin.workerd.mjs.map +0 -7
- package/dist/lib/neutral/app-graph-builder-GQRMI22E.mjs +0 -48
- package/dist/lib/neutral/app-graph-builder-GQRMI22E.mjs.map +0 -7
- package/dist/lib/neutral/capabilities/index.mjs +0 -31
- package/dist/lib/neutral/capabilities/index.mjs.map +0 -7
- package/dist/lib/neutral/chunk-5BVHY75B.mjs.map +0 -7
- package/dist/lib/neutral/chunk-HNXSU7HJ.mjs +0 -8
- package/dist/lib/neutral/chunk-HNXSU7HJ.mjs.map +0 -7
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs +0 -10
- package/dist/lib/neutral/chunk-J5LGTIGS.mjs.map +0 -7
- package/dist/lib/neutral/chunk-KOXLGGSL.mjs +0 -30
- package/dist/lib/neutral/chunk-KOXLGGSL.mjs.map +0 -7
- package/dist/lib/neutral/chunk-MDV7NBFJ.mjs +0 -182
- package/dist/lib/neutral/chunk-MDV7NBFJ.mjs.map +0 -7
- package/dist/lib/neutral/components/index.mjs +0 -125
- package/dist/lib/neutral/components/index.mjs.map +0 -7
- package/dist/lib/neutral/containers/index.mjs +0 -9
- package/dist/lib/neutral/containers/index.mjs.map +0 -7
- package/dist/lib/neutral/create-HNHGCKZ4.mjs +0 -21
- package/dist/lib/neutral/create-HNHGCKZ4.mjs.map +0 -7
- package/dist/lib/neutral/enrich-message-DSJU4TXC.mjs +0 -24
- package/dist/lib/neutral/enrich-message-DSJU4TXC.mjs.map +0 -7
- package/dist/lib/neutral/entity-lookup-PCDW7NC4.mjs +0 -25
- package/dist/lib/neutral/entity-lookup-PCDW7NC4.mjs.map +0 -7
- package/dist/lib/neutral/hooks/index.mjs +0 -97
- package/dist/lib/neutral/hooks/index.mjs.map +0 -7
- package/dist/lib/neutral/index.mjs +0 -20
- package/dist/lib/neutral/index.mjs.map +0 -7
- package/dist/lib/neutral/markdown-extension-CCDXXY7E.mjs.map +0 -7
- package/dist/lib/neutral/meta.json +0 -1
- package/dist/lib/neutral/meta.mjs +0 -8
- package/dist/lib/neutral/meta.mjs.map +0 -7
- package/dist/lib/neutral/open-SNMZXXYO.mjs +0 -25
- package/dist/lib/neutral/open-SNMZXXYO.mjs.map +0 -7
- package/dist/lib/neutral/operation-handler-NXMOAXFP.mjs +0 -13
- package/dist/lib/neutral/operation-handler-NXMOAXFP.mjs.map +0 -7
- package/dist/lib/neutral/operations/index.mjs +0 -8
- package/dist/lib/neutral/operations/index.mjs.map +0 -7
- package/dist/lib/neutral/pipeline-status-XMWMAUJY.mjs +0 -17
- package/dist/lib/neutral/pipeline-status-XMWMAUJY.mjs.map +0 -7
- package/dist/lib/neutral/plugin.mjs +0 -16
- package/dist/lib/neutral/plugin.mjs.map +0 -7
- package/dist/lib/neutral/react-surface-YMZRO242.mjs +0 -26
- package/dist/lib/neutral/react-surface-YMZRO242.mjs.map +0 -7
- package/dist/lib/neutral/recording-session-IADO7ATU.mjs +0 -15
- package/dist/lib/neutral/recording-session-IADO7ATU.mjs.map +0 -7
- package/dist/lib/neutral/settings-7KE4MABW.mjs +0 -31
- package/dist/lib/neutral/settings-7KE4MABW.mjs.map +0 -7
- package/dist/lib/neutral/skill-definition-DXNK324V.mjs +0 -15
- package/dist/lib/neutral/skill-definition-DXNK324V.mjs.map +0 -7
- package/dist/lib/neutral/skills/index.mjs +0 -8
- package/dist/lib/neutral/skills/index.mjs.map +0 -7
- package/dist/lib/neutral/summarize-LBUZTOTH.mjs.map +0 -7
- package/dist/lib/neutral/text-content-NOWR642C.mjs +0 -30
- package/dist/lib/neutral/text-content-NOWR642C.mjs.map +0 -7
- package/dist/lib/neutral/transcriber-6XZHUUHK.mjs +0 -174
- package/dist/lib/neutral/transcriber-6XZHUUHK.mjs.map +0 -7
- package/dist/lib/neutral/transcription-driver-DN6ELQXZ.mjs +0 -207
- package/dist/lib/neutral/transcription-driver-DN6ELQXZ.mjs.map +0 -7
- package/dist/lib/neutral/translations.mjs +0 -31
- package/dist/lib/neutral/translations.mjs.map +0 -7
- package/dist/lib/neutral/types/index.mjs +0 -12
- package/dist/lib/neutral/types/index.mjs.map +0 -7
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { Capability } from "@dxos/app-framework";
|
|
2
|
+
import { Operation } from "@dxos/compute";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import { meta } from "#meta";
|
|
5
|
+
import { AiService } from "@dxos/ai";
|
|
6
|
+
import { SpaceSchema } from "@dxos/client/echo";
|
|
7
|
+
import { DXN, Database, Ref, Type } from "@dxos/echo";
|
|
8
|
+
import { Message, Transcript } from "@dxos/types";
|
|
9
|
+
//#region \0rolldown/runtime.js
|
|
10
|
+
var __defProp = Object.defineProperty;
|
|
11
|
+
var __exportAll = (all, no_symbols) => {
|
|
12
|
+
let target = {};
|
|
13
|
+
for (var name in all) __defProp(target, name, {
|
|
14
|
+
get: all[name],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
18
|
+
return target;
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/types/Settings.ts
|
|
22
|
+
var Settings_exports = /* @__PURE__ */ __exportAll({ Settings: () => Settings$1 });
|
|
23
|
+
var Settings$1 = Schema.mutable(Schema.Struct({
|
|
24
|
+
entityExtraction: Schema.optional(Schema.Boolean.annotations({
|
|
25
|
+
title: "Entity extraction",
|
|
26
|
+
description: "While transcribing, use the Assistant to detect and annotate mentions of known objects such as people or organizations."
|
|
27
|
+
})).pipe(Schema.withConstructorDefault(() => true)),
|
|
28
|
+
recordMode: Schema.optional(Schema.Literal("toggle", "hold").annotations({
|
|
29
|
+
title: "Record mode",
|
|
30
|
+
description: "Whether the mic toggles recording on each click, or records only while the control is held (push-to-talk)."
|
|
31
|
+
})).pipe(Schema.withConstructorDefault(() => "toggle")),
|
|
32
|
+
audioDeviceId: Schema.optional(Schema.String.annotations({
|
|
33
|
+
title: "Audio input device",
|
|
34
|
+
description: "Identifier of the microphone to capture from; empty uses the system default."
|
|
35
|
+
})),
|
|
36
|
+
transcribeAfterMs: Schema.optional(Schema.Number.annotations({
|
|
37
|
+
title: "Initial buffering (ms)",
|
|
38
|
+
description: "How long to accumulate audio before producing the first transcription."
|
|
39
|
+
})).pipe(Schema.withConstructorDefault(() => 4e3)),
|
|
40
|
+
streamMode: Schema.optional(Schema.Literal("batch", "word").annotations({
|
|
41
|
+
title: "Reveal mode",
|
|
42
|
+
description: "Whether transcribed text appears in batches or streams word-by-word."
|
|
43
|
+
})).pipe(Schema.withConstructorDefault(() => "word")),
|
|
44
|
+
wordIntervalMs: Schema.optional(Schema.Number.annotations({
|
|
45
|
+
title: "Word interval (ms)",
|
|
46
|
+
description: "Pacing between words when streaming word-by-word."
|
|
47
|
+
})).pipe(Schema.withConstructorDefault(() => 80))
|
|
48
|
+
}));
|
|
49
|
+
//#endregion
|
|
50
|
+
//#region src/types/TranscriptionCapabilities.ts
|
|
51
|
+
var TranscriptionCapabilities_exports = /* @__PURE__ */ __exportAll({
|
|
52
|
+
EntityLookup: () => EntityLookup,
|
|
53
|
+
PipelineStatus: () => PipelineStatus,
|
|
54
|
+
RecordingSession: () => RecordingSession,
|
|
55
|
+
Settings: () => Settings,
|
|
56
|
+
TranscriptionManagerProvider: () => TranscriptionManagerProvider
|
|
57
|
+
});
|
|
58
|
+
var TranscriptionManagerProvider = Capability.make(`${meta.profile.key}.capability.transcription-manager`);
|
|
59
|
+
var Settings = Capability.make(`${meta.profile.key}.capability.settings`);
|
|
60
|
+
var RecordingSession = Capability.make(`${meta.profile.key}.capability.recording-session`);
|
|
61
|
+
var EntityLookup = Capability.make(`${meta.profile.key}.capability.entity-lookup`);
|
|
62
|
+
var PipelineStatus = Capability.make(`${meta.profile.key}.capability.pipeline-status`);
|
|
63
|
+
//#endregion
|
|
64
|
+
//#region src/types/TranscriptOperation.ts
|
|
65
|
+
var TranscriptOperation_exports = /* @__PURE__ */ __exportAll({
|
|
66
|
+
Create: () => Create,
|
|
67
|
+
EnrichMessage: () => EnrichMessage,
|
|
68
|
+
MessageWithRangeId: () => MessageWithRangeId,
|
|
69
|
+
Open: () => Open,
|
|
70
|
+
SentenceNormalization: () => SentenceNormalization,
|
|
71
|
+
SentenceNormalizationInput: () => SentenceNormalizationInput,
|
|
72
|
+
SentenceNormalizationOutput: () => SentenceNormalizationOutput,
|
|
73
|
+
Summarize: () => Summarize
|
|
74
|
+
});
|
|
75
|
+
var makeKey = (name) => DXN.make(`${meta.profile.key}.operation.${name}`);
|
|
76
|
+
var Create = Operation.make({
|
|
77
|
+
meta: {
|
|
78
|
+
key: makeKey("create"),
|
|
79
|
+
name: "Create Transcript",
|
|
80
|
+
icon: "ph--microphone--regular"
|
|
81
|
+
},
|
|
82
|
+
input: Schema.Struct({
|
|
83
|
+
name: Schema.optional(Schema.String),
|
|
84
|
+
space: SpaceSchema
|
|
85
|
+
}),
|
|
86
|
+
output: Schema.Struct({ object: Type.getSchema(Transcript.Transcript) })
|
|
87
|
+
});
|
|
88
|
+
var MessageWithRangeId = Schema.extend(Type.getSchema(Message.Message), Schema.Struct({ rangeId: Schema.optional(Schema.Array(Schema.String)).annotations({ description: "The IDs of the messages that contain the sentences." }) }));
|
|
89
|
+
var Open = Operation.make({
|
|
90
|
+
meta: {
|
|
91
|
+
key: DXN.make("org.dxos.function.transcription.open"),
|
|
92
|
+
name: "Open",
|
|
93
|
+
description: "Opens and reads the contents of a transcription object.",
|
|
94
|
+
icon: "ph--folder-open--regular"
|
|
95
|
+
},
|
|
96
|
+
input: Schema.Struct({ transcript: Ref.Ref(Transcript.Transcript).annotations({ description: "The ID of the transcription object." }) }),
|
|
97
|
+
output: Schema.Struct({ content: Schema.String }),
|
|
98
|
+
services: [Database.Service]
|
|
99
|
+
});
|
|
100
|
+
var Summarize = Operation.make({
|
|
101
|
+
meta: {
|
|
102
|
+
key: DXN.make("org.dxos.function.transcription.summarize"),
|
|
103
|
+
name: "Summarize",
|
|
104
|
+
description: "Summarize a transcript of a meeting.",
|
|
105
|
+
icon: "ph--text-align-left--regular"
|
|
106
|
+
},
|
|
107
|
+
input: Schema.Struct({
|
|
108
|
+
transcript: Schema.String.annotations({ description: "The transcript of the meeting." }),
|
|
109
|
+
notes: Schema.optional(Schema.String).annotations({ description: "Additional notes from the participants." })
|
|
110
|
+
}),
|
|
111
|
+
output: Schema.Struct({ summary: Schema.String.annotations({ description: "The summary of the transcript." }) }),
|
|
112
|
+
services: [AiService.AiService]
|
|
113
|
+
}).pipe(Operation.visible);
|
|
114
|
+
var EnrichMessage = Operation.make({
|
|
115
|
+
meta: {
|
|
116
|
+
key: DXN.make("org.dxos.function.transcription.enrichMessage"),
|
|
117
|
+
name: "Enrich Transcript Message",
|
|
118
|
+
description: "Extract proper nouns from a transcript message and link them to objects in the space.",
|
|
119
|
+
icon: "ph--text-t--regular"
|
|
120
|
+
},
|
|
121
|
+
input: Schema.Struct({ message: Type.getSchema(Message.Message) }),
|
|
122
|
+
output: Schema.Struct({ message: Type.getSchema(Message.Message) }),
|
|
123
|
+
services: [AiService.AiService, Database.Service]
|
|
124
|
+
});
|
|
125
|
+
var SentenceNormalizationInput = Schema.Struct({ messages: Schema.Array(MessageWithRangeId).annotations({ description: "Messages to normalize into sentences." }) });
|
|
126
|
+
var SentenceNormalizationOutput = Schema.Struct({ sentences: Schema.Array(MessageWithRangeId.pipe(Schema.mutable)).pipe(Schema.mutable).annotations({ description: "The sentences of the transcript." }) });
|
|
127
|
+
var SentenceNormalization = Operation.make({
|
|
128
|
+
meta: {
|
|
129
|
+
key: DXN.make("org.dxos.function.transcription.sentenceNormalization"),
|
|
130
|
+
name: "Sentence Normalization",
|
|
131
|
+
description: "Post process of transcription for sentence normalization",
|
|
132
|
+
icon: "ph--text-t--regular"
|
|
133
|
+
},
|
|
134
|
+
input: SentenceNormalizationInput,
|
|
135
|
+
output: SentenceNormalizationOutput,
|
|
136
|
+
services: []
|
|
137
|
+
});
|
|
138
|
+
//#endregion
|
|
139
|
+
export { TranscriptOperation_exports as a, Summarize as i, EnrichMessage as n, TranscriptionCapabilities_exports as o, Open as r, Settings_exports as s, Create as t };
|
|
140
|
+
|
|
141
|
+
//# sourceMappingURL=chunk-types.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunk-types.mjs","names":[],"sources":["../../src/types/Settings.ts","../../src/types/TranscriptionCapabilities.ts","../../src/types/TranscriptOperation.ts"],"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';\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/pipeline-transcription';\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"],"mappings":"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"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { TranscriptionCapabilities } from "#types";
|
|
2
|
+
import { meta } from "#meta";
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
|
+
import { useAtomCapabilityState } from "@dxos/app-framework/ui";
|
|
5
|
+
import { MicButton, useTranslation } from "@dxos/react-ui";
|
|
6
|
+
import { useSoundEffect } from "@dxos/react-ui-audio";
|
|
7
|
+
import { MicSettings } from "@dxos/react-ui-transcription";
|
|
8
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
//#region src/components/Mic/Mic.tsx
|
|
10
|
+
/**
|
|
11
|
+
* Connects the {@link MicButton} and {@link MicSettings} to the recording session and settings
|
|
12
|
+
* capabilities, and enumerates available audio inputs. Mounted from the toolbar's custom action, so
|
|
13
|
+
* capability hooks resolve.
|
|
14
|
+
*/
|
|
15
|
+
var Mic = ({ docId }) => {
|
|
16
|
+
const { t } = useTranslation(meta.profile.key);
|
|
17
|
+
const [session, setSession] = useAtomCapabilityState(TranscriptionCapabilities.RecordingSession);
|
|
18
|
+
const [settings, setSettings] = useAtomCapabilityState(TranscriptionCapabilities.Settings);
|
|
19
|
+
const recording = !!session?.recording && session.id === docId;
|
|
20
|
+
const soundStart = useSoundEffect("StartRecording");
|
|
21
|
+
const soundStop = useSoundEffect("StopRecording");
|
|
22
|
+
const wasRecording = useRef(recording);
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (wasRecording.current === recording) return;
|
|
25
|
+
wasRecording.current = recording;
|
|
26
|
+
(recording ? soundStart : soundStop).play();
|
|
27
|
+
}, [
|
|
28
|
+
recording,
|
|
29
|
+
soundStart,
|
|
30
|
+
soundStop
|
|
31
|
+
]);
|
|
32
|
+
const recordMode = settings?.recordMode ?? "toggle";
|
|
33
|
+
const entityExtraction = settings?.entityExtraction !== false;
|
|
34
|
+
const selectedDeviceId = settings?.audioDeviceId ?? "";
|
|
35
|
+
const [devices, setDevices] = useState([]);
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
if (!navigator.mediaDevices?.enumerateDevices) return;
|
|
38
|
+
let cancelled = false;
|
|
39
|
+
const refresh = async () => {
|
|
40
|
+
const all = await navigator.mediaDevices.enumerateDevices();
|
|
41
|
+
if (cancelled) return;
|
|
42
|
+
setDevices(all.filter((device) => device.kind === "audioinput" && device.deviceId).map((device, index) => ({
|
|
43
|
+
deviceId: device.deviceId,
|
|
44
|
+
label: device.label || `Microphone ${index + 1}`
|
|
45
|
+
})));
|
|
46
|
+
};
|
|
47
|
+
refresh();
|
|
48
|
+
navigator.mediaDevices.addEventListener("devicechange", refresh);
|
|
49
|
+
return () => {
|
|
50
|
+
cancelled = true;
|
|
51
|
+
navigator.mediaDevices.removeEventListener("devicechange", refresh);
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
const handleToggle = useCallback(() => {
|
|
55
|
+
setSession((current) => current?.recording && current.id === docId ? null : {
|
|
56
|
+
id: docId,
|
|
57
|
+
recording: true
|
|
58
|
+
});
|
|
59
|
+
}, [setSession, docId]);
|
|
60
|
+
const handlePressStart = useCallback(() => {
|
|
61
|
+
setSession(() => ({
|
|
62
|
+
id: docId,
|
|
63
|
+
recording: true
|
|
64
|
+
}));
|
|
65
|
+
}, [setSession, docId]);
|
|
66
|
+
const handlePressEnd = useCallback(() => {
|
|
67
|
+
setSession((current) => current?.id === docId ? null : current);
|
|
68
|
+
}, [setSession, docId]);
|
|
69
|
+
const handleRecordModeChange = useCallback((mode) => setSettings((current) => ({
|
|
70
|
+
...current,
|
|
71
|
+
recordMode: mode
|
|
72
|
+
})), [setSettings]);
|
|
73
|
+
const handleEntityExtractionChange = useCallback((value) => setSettings((current) => ({
|
|
74
|
+
...current,
|
|
75
|
+
entityExtraction: value
|
|
76
|
+
})), [setSettings]);
|
|
77
|
+
const handleSelectDevice = useCallback((deviceId) => setSettings((current) => ({
|
|
78
|
+
...current,
|
|
79
|
+
audioDeviceId: deviceId || void 0
|
|
80
|
+
})), [setSettings]);
|
|
81
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
82
|
+
className: "flex items-center",
|
|
83
|
+
children: [/* @__PURE__ */ jsx(MicButton, {
|
|
84
|
+
iconOnly: true,
|
|
85
|
+
variant: "ghost",
|
|
86
|
+
label: recording ? t("stop-recording.label") : recordMode === "hold" ? t("hold-to-record.label") : t("start-recording.label"),
|
|
87
|
+
recording,
|
|
88
|
+
mode: recordMode,
|
|
89
|
+
onToggle: handleToggle,
|
|
90
|
+
onPressStart: handlePressStart,
|
|
91
|
+
onPressEnd: handlePressEnd,
|
|
92
|
+
"data-testid": "transcription.record"
|
|
93
|
+
}), /* @__PURE__ */ jsx(MicSettings, {
|
|
94
|
+
translationNs: meta.profile.key,
|
|
95
|
+
recordMode,
|
|
96
|
+
entityExtraction,
|
|
97
|
+
devices,
|
|
98
|
+
selectedDeviceId,
|
|
99
|
+
onRecordModeChange: handleRecordModeChange,
|
|
100
|
+
onEntityExtractionChange: handleEntityExtractionChange,
|
|
101
|
+
onSelectDevice: handleSelectDevice
|
|
102
|
+
})]
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
//#endregion
|
|
106
|
+
export { Mic };
|
|
107
|
+
|
|
108
|
+
//# sourceMappingURL=components.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.mjs","names":[],"sources":["../../src/components/Mic/Mic.tsx"],"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"],"mappings":";;;;;;;;;;;;;;AAwBA,IAAa,OAAO,EAAE,YAAsB;CAC1C,MAAM,EAAE,MAAM,eAAe,KAAK,QAAQ,GAAG;CAC7C,MAAM,CAAC,SAAS,cAAc,uBAAuB,0BAA0B,gBAAgB;CAC/F,MAAM,CAAC,UAAU,eAAe,uBAAuB,0BAA0B,QAAQ;CAEzF,MAAM,YAAY,CAAC,CAAC,SAAS,aAAa,QAAQ,OAAO;CAGzD,MAAM,aAAa,eAAe,gBAAgB;CAClD,MAAM,YAAY,eAAe,eAAe;CAChD,MAAM,eAAe,OAAO,SAAS;CACrC,gBAAgB;EACd,IAAI,aAAa,YAAY,WAC3B;EAEF,aAAa,UAAU;EACvB,CAAM,YAAY,aAAa,UAAA,CAAW,KAAK;CACjD,GAAG;EAAC;EAAW;EAAY;CAAS,CAAC;CAErC,MAAM,aAAkC,UAAU,cAAc;CAChE,MAAM,mBAAmB,UAAU,qBAAqB;CACxD,MAAM,mBAAmB,UAAU,iBAAiB;CAEpD,MAAM,CAAC,SAAS,cAAc,SAA6B,CAAC,CAAC;CAC7D,gBAAgB;EACd,IAAI,CAAC,UAAU,cAAc,kBAC3B;EAEF,IAAI,YAAY;EAChB,MAAM,UAAU,YAAY;GAC1B,MAAM,MAAM,MAAM,UAAU,aAAa,iBAAiB;GAC1D,IAAI,WACF;GAGF,WACE,IACG,QAAQ,WAAW,OAAO,SAAS,gBAAgB,OAAO,QAAQ,CAAA,CAClE,KAAK,QAAQ,WAAW;IACvB,UAAU,OAAO;IACjB,OAAO,OAAO,SAAS,cAAc,QAAQ;GAC/C,EAAE,CACN;EACF;EACA,QAAa;EACb,UAAU,aAAa,iBAAiB,gBAAgB,OAAO;EAC/D,aAAa;GACX,YAAY;GACZ,UAAU,aAAa,oBAAoB,gBAAgB,OAAO;EACpE;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,eAAe,kBAAkB;EACrC,YAAY,YAAa,SAAS,aAAa,QAAQ,OAAO,QAAQ,OAAO;GAAE,IAAI;GAAO,WAAW;EAAK,CAAE;CAC9G,GAAG,CAAC,YAAY,KAAK,CAAC;CAEtB,MAAM,mBAAmB,kBAAkB;EACzC,kBAAkB;GAAE,IAAI;GAAO,WAAW;EAAK,EAAE;CACnD,GAAG,CAAC,YAAY,KAAK,CAAC;CAEtB,MAAM,iBAAiB,kBAAkB;EAEvC,YAAY,YAAa,SAAS,OAAO,QAAQ,OAAO,OAAQ;CAClE,GAAG,CAAC,YAAY,KAAK,CAAC;CAEtB,MAAM,yBAAyB,aAC5B,SAA8B,aAAa,aAAa;EAAE,GAAG;EAAS,YAAY;CAAK,EAAE,GAC1F,CAAC,WAAW,CACd;CAEA,MAAM,+BAA+B,aAClC,UAAmB,aAAa,aAAa;EAAE,GAAG;EAAS,kBAAkB;CAAM,EAAE,GACtF,CAAC,WAAW,CACd;CAEA,MAAM,qBAAqB,aACxB,aAAqB,aAAa,aAAa;EAAE,GAAG;EAAS,eAAe,YAAY,KAAA;CAAU,EAAE,GACrG,CAAC,WAAW,CACd;CAQA,OACE,qBAAC,OAAD;EAAK,WAAU;YAAf,CACE,oBAAC,WAAD;GACE,UAAA;GACA,SAAQ;GACR,OAXc,YAChB,EAAE,sBAAsB,IACxB,eAAe,SACb,EAAE,sBAAsB,IACxB,EAAE,uBAAuB;GAQd;GACX,MAAM;GACN,UAAU;GACV,cAAc;GACd,YAAY;GACZ,eAAY;EACb,CAAA,GACD,oBAAC,aAAD;GACE,eAAe,KAAK,QAAQ;GAChB;GACM;GACT;GACS;GAClB,oBAAoB;GACpB,0BAA0B;GAC1B,gBAAgB;EACjB,CAAA,CACE;;AAET"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containers.mjs","names":[],"sources":["../../src/containers/index.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport { type ComponentType, lazy } from 'react';\n\nexport const TranscriptionArticle: ComponentType<any> = lazy(() => import('./TranscriptionArticle'));\n"],"mappings":";;AAMA,IAAa,uBAA2C,WAAW,OAAO,mCAAyB"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { TranscriptOperation, TranscriptionCapabilities } from "#types";
|
|
2
|
+
import { Database, Feed, Obj } from "@dxos/echo";
|
|
3
|
+
import { Message } from "@dxos/types";
|
|
4
|
+
import { useCallback, useEffect, useState } from "react";
|
|
5
|
+
import { useAtomCapability, useOperationInvoker } from "@dxos/app-framework/ui";
|
|
6
|
+
import { useAudioTrack, useTranscriber } from "@dxos/react-ui-transcription";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import { EffectEx } from "@dxos/effect";
|
|
9
|
+
import { useIdentity } from "@dxos/halo-react";
|
|
10
|
+
import { log } from "@dxos/log";
|
|
11
|
+
//#region src/hooks/useTranscriptionRecording.ts
|
|
12
|
+
var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transcription/src/hooks/useTranscriptionRecording.ts";
|
|
13
|
+
/**
|
|
14
|
+
* Drives the recording lifecycle for a transcript: opens an audio track, feeds it through the
|
|
15
|
+
* transcriber, and appends transcribed message batches to the transcript's feed. Returns the
|
|
16
|
+
* recording flag and a toggle callback for the caller to wire to UI.
|
|
17
|
+
*/
|
|
18
|
+
var useTranscriptionRecording = (transcript) => {
|
|
19
|
+
const db = Obj.getDatabase(transcript);
|
|
20
|
+
const identity = useIdentity();
|
|
21
|
+
const feed = transcript.feed.target;
|
|
22
|
+
const [recording, setRecording] = useState(false);
|
|
23
|
+
const track = useAudioTrack(recording);
|
|
24
|
+
const { invokePromise } = useOperationInvoker();
|
|
25
|
+
const settings = useAtomCapability(TranscriptionCapabilities.Settings);
|
|
26
|
+
const transcriber = useTranscriber({
|
|
27
|
+
audioStreamTrack: track,
|
|
28
|
+
onSegments: useCallback(async (blocks) => {
|
|
29
|
+
if (!db || !feed || blocks.length === 0) return;
|
|
30
|
+
const sender = identity ? {
|
|
31
|
+
identityDid: identity.did,
|
|
32
|
+
name: identity.displayName
|
|
33
|
+
} : {};
|
|
34
|
+
let message = Obj.make(Message.Message, {
|
|
35
|
+
sender,
|
|
36
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
37
|
+
blocks
|
|
38
|
+
});
|
|
39
|
+
if (settings?.entityExtraction ?? true) {
|
|
40
|
+
const { data, error } = await invokePromise(TranscriptOperation.EnrichMessage, { message }, { spaceId: db.spaceId });
|
|
41
|
+
if (error) log.warn("entity extraction failed; using raw transcript", { error }, {
|
|
42
|
+
"~LogMeta": "~LogMeta",
|
|
43
|
+
F: __dxlog_file,
|
|
44
|
+
L: 61,
|
|
45
|
+
S: void 0
|
|
46
|
+
});
|
|
47
|
+
else if (data?.message) message = data.message;
|
|
48
|
+
}
|
|
49
|
+
await Feed.append(feed, [message]).pipe(Effect.provide(Database.layer(db)), EffectEx.runAndForwardErrors);
|
|
50
|
+
}, [
|
|
51
|
+
db,
|
|
52
|
+
feed,
|
|
53
|
+
identity,
|
|
54
|
+
invokePromise,
|
|
55
|
+
settings
|
|
56
|
+
])
|
|
57
|
+
});
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (!transcriber) return;
|
|
60
|
+
let cancelled = false;
|
|
61
|
+
transcriber.open().then(() => {
|
|
62
|
+
if (!cancelled && recording) transcriber.startChunksRecording();
|
|
63
|
+
}, (err) => {
|
|
64
|
+
if (!cancelled) {
|
|
65
|
+
log.catch(err, void 0, {
|
|
66
|
+
"~LogMeta": "~LogMeta",
|
|
67
|
+
F: __dxlog_file,
|
|
68
|
+
L: 90,
|
|
69
|
+
S: void 0
|
|
70
|
+
});
|
|
71
|
+
setRecording(false);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return () => {
|
|
75
|
+
cancelled = true;
|
|
76
|
+
transcriber.stopChunksRecording();
|
|
77
|
+
};
|
|
78
|
+
}, [transcriber, recording]);
|
|
79
|
+
return {
|
|
80
|
+
recording,
|
|
81
|
+
toggleRecording: useCallback(() => setRecording((value) => !value), [])
|
|
82
|
+
};
|
|
83
|
+
};
|
|
84
|
+
//#endregion
|
|
85
|
+
export { useTranscriptionRecording };
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=hooks.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.mjs","names":[],"sources":["../../src/hooks/useTranscriptionRecording.ts"],"sourcesContent":["//\n// Copyright 2024 DXOS.org\n//\n\nimport * as Effect from 'effect/Effect';\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { useAtomCapability, useOperationInvoker } from '@dxos/app-framework/ui';\nimport { Database, Feed, Obj } from '@dxos/echo';\nimport { EffectEx } from '@dxos/effect';\nimport { useIdentity } from '@dxos/halo-react';\nimport { log } from '@dxos/log';\nimport { useAudioTrack, useTranscriber } from '@dxos/react-ui-transcription';\nimport { Message, type Transcript } from '@dxos/types';\n\nimport { TranscriptionCapabilities, TranscriptOperation } from '#types';\n\nexport type TranscriptionRecording = {\n recording: boolean;\n toggleRecording: () => void;\n};\n\n/**\n * Drives the recording lifecycle for a transcript: opens an audio track, feeds it through the\n * transcriber, and appends transcribed message batches to the transcript's feed. Returns the\n * recording flag and a toggle callback for the caller to wire to UI.\n */\nexport const useTranscriptionRecording = (transcript: Transcript.Transcript): TranscriptionRecording => {\n const db = Obj.getDatabase(transcript);\n const identity = useIdentity();\n const feed = transcript.feed.target;\n\n const [recording, setRecording] = useState(false);\n const track = useAudioTrack(recording);\n const { invokePromise } = useOperationInvoker();\n const settings = useAtomCapability(TranscriptionCapabilities.Settings);\n\n // Append a transcribed message batch to the transcript's feed, enriching it first (when entity\n // extraction is enabled) with references to known entities mentioned in the transcript.\n const handleSegments = useCallback(\n async (blocks: Message.Message['blocks']) => {\n if (!db || !feed || blocks.length === 0) {\n return;\n }\n const sender = identity ? { identityDid: identity.did, name: identity.displayName } : {};\n let message = Obj.make(Message.Message, {\n sender,\n created: new Date().toISOString(),\n blocks,\n });\n\n // `spaceId` provides the space context required by the process-affinity AiService/Database.\n // Fall back to the raw message if extraction fails (e.g. AI service unavailable).\n if (settings?.entityExtraction ?? true) {\n const { data, error } = await invokePromise(\n TranscriptOperation.EnrichMessage,\n { message },\n { spaceId: db.spaceId },\n );\n if (error) {\n log.warn('entity extraction failed; using raw transcript', { error });\n } else if (data?.message) {\n message = data.message;\n }\n }\n\n await Feed.append(feed, [message]).pipe(Effect.provide(Database.layer(db)), EffectEx.runAndForwardErrors);\n },\n [db, feed, identity, invokePromise, settings],\n );\n\n // Drive the transcriber lifecycle off the recording flag + audio track.\n const transcriber = useTranscriber({ audioStreamTrack: track, onSegments: handleSegments });\n useEffect(() => {\n if (!transcriber) {\n return;\n }\n let cancelled = false;\n // If `open()` rejects (e.g. mic permission denied, device init failure) we must\n // clear `recording` — otherwise the toolbar button reports \"stop\" forever while\n // nothing is actually being captured.\n void transcriber.open().then(\n () => {\n if (!cancelled && recording) {\n transcriber.startChunksRecording();\n }\n },\n (err) => {\n if (!cancelled) {\n log.catch(err);\n setRecording(false);\n }\n },\n );\n return () => {\n cancelled = true;\n transcriber.stopChunksRecording();\n };\n }, [transcriber, recording]);\n\n const toggleRecording = useCallback(() => setRecording((value) => !value), []);\n\n return { recording, toggleRecording };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,IAAa,6BAA6B,eAA8D;CACtG,MAAM,KAAK,IAAI,YAAY,UAAU;CACrC,MAAM,WAAW,YAAY;CAC7B,MAAM,OAAO,WAAW,KAAK;CAE7B,MAAM,CAAC,WAAW,gBAAgB,SAAS,KAAK;CAChD,MAAM,QAAQ,cAAc,SAAS;CACrC,MAAM,EAAE,kBAAkB,oBAAoB;CAC9C,MAAM,WAAW,kBAAkB,0BAA0B,QAAQ;CAqCrE,MAAM,cAAc,eAAe;EAAE,kBAAkB;EAAO,YAjCvC,YACrB,OAAO,WAAsC;GAC3C,IAAI,CAAC,MAAM,CAAC,QAAQ,OAAO,WAAW,GACpC;GAEF,MAAM,SAAS,WAAW;IAAE,aAAa,SAAS;IAAK,MAAM,SAAS;GAAY,IAAI,CAAC;GACvF,IAAI,UAAU,IAAI,KAAK,QAAQ,SAAS;IACtC;IACA,0BAAS,IAAI,KAAK,EAAA,CAAE,YAAY;IAChC;GACF,CAAC;GAID,IAAI,UAAU,oBAAoB,MAAM;IACtC,MAAM,EAAE,MAAM,UAAU,MAAM,cAC5B,oBAAoB,eACpB,EAAE,QAAQ,GACV,EAAE,SAAS,GAAG,QAAQ,CACxB;IACA,IAAI,OACF,IAAI,KAAK,kDAAkD,EAAE,MAAM,GAAA;KAAA,YAAA;KAAA,GAAA;KAAA,GAAA;KAAA,GAAA,KAAA;IAAA,CAAC;SAC/D,IAAI,MAAM,SACf,UAAU,KAAK;GAEnB;GAEA,MAAM,KAAK,OAAO,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,QAAQ,SAAS,MAAM,EAAE,CAAC,GAAG,SAAS,mBAAmB;EAC1G,GACA;GAAC;GAAI;GAAM;GAAU;GAAe;EAAQ,CAI4B;CAAe,CAAC;CAC1F,gBAAgB;EACd,IAAI,CAAC,aACH;EAEF,IAAI,YAAY;EAIhB,YAAiB,KAAK,CAAC,CAAC,WAChB;GACJ,IAAI,CAAC,aAAa,WAChB,YAAY,qBAAqB;EAErC,IACC,QAAQ;GACP,IAAI,CAAC,WAAW;IACd,IAAI,MAAM,KAAE,KAAA,GAAA;KAAA,YAAA;KAAA,GAAA;KAAA,GAAA;KAAA,GAAA,KAAA;IAAA,CAAC;IACb,aAAa,KAAK;GACpB;EACF,CACF;EACA,aAAa;GACX,YAAY;GACZ,YAAY,oBAAoB;EAClC;CACF,GAAG,CAAC,aAAa,SAAS,CAAC;CAI3B,OAAO;EAAE;EAAW,iBAFI,kBAAkB,cAAc,UAAU,CAAC,KAAK,GAAG,CAAC,CAExD;CAAgB;AACtC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { a as TranscriptOperation_exports, o as TranscriptionCapabilities_exports, s as Settings_exports } from "./chunk-types.mjs";
|
|
2
|
+
import { t as meta } from "./chunk-meta.mjs";
|
|
3
|
+
import { t as skill } from "./chunk-skills.mjs";
|
|
4
|
+
export { Settings_exports as Settings, TranscriptOperation_exports as TranscriptOperation, TranscriptionCapabilities_exports as TranscriptionCapabilities, skill as TranscriptionSkill, meta };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { OperationHandlerSet } from "@dxos/compute";
|
|
2
|
+
//#region src/operations/index.ts
|
|
3
|
+
var TranscriptionOperationHandlerSet = OperationHandlerSet.lazy(() => import("./chunk-create.mjs"), () => import("./chunk-open.mjs"), () => import("./chunk-summarize.mjs"), () => import("./chunk-enrich-message.mjs"));
|
|
4
|
+
//#endregion
|
|
5
|
+
export { TranscriptionOperationHandlerSet };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=operations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operations.mjs","names":[],"sources":["../../src/operations/index.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { OperationHandlerSet } from '@dxos/compute';\n\nexport const TranscriptionOperationHandlerSet = OperationHandlerSet.lazy(\n () => import('./create'),\n () => import('./open'),\n () => import('./summarize'),\n () => import('./enrich-message'),\n);\n"],"mappings":";;AAMA,IAAa,mCAAmC,oBAAoB,WAC5D,OAAO,6BACP,OAAO,2BACP,OAAO,gCACP,OAAO,6BACf"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { t as meta } from "./chunk-meta.mjs";
|
|
2
|
+
import { TranscriptionOperationHandlerSet } from "./operations.mjs";
|
|
3
|
+
import { Plugin } from "@dxos/app-framework";
|
|
4
|
+
//#region src/plugin.ts
|
|
5
|
+
var TranscriptionPlugin = Plugin.lazy(meta, () => import("#plugin"));
|
|
6
|
+
//#endregion
|
|
7
|
+
export { TranscriptionOperationHandlerSet, TranscriptionPlugin };
|
|
8
|
+
|
|
9
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.mjs","names":[],"sources":["../../src/plugin.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\n\nimport { meta } from './meta';\n\nexport const TranscriptionPlugin = Plugin.lazy(meta, () => import('#plugin'));\n\nexport { TranscriptionOperationHandlerSet } from './operations';\n"],"mappings":";;;;AAQA,IAAa,sBAAsB,OAAO,KAAK,YAAY,OAAO,UAAU"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { t as TranscriptionPlugin } from "./chunk-TranscriptionPlugin.mjs";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import { DXN, Obj, Ref, Type } from "@dxos/echo";
|
|
4
|
+
import { Message, Organization, Person } from "@dxos/types";
|
|
5
|
+
import { AppActivationEvents } from "@dxos/app-toolkit";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import { withPluginManager } from "@dxos/app-framework/testing";
|
|
8
|
+
import { ClientPlugin, initializeIdentity } from "@dxos/plugin-client/testing";
|
|
9
|
+
import { PreviewPlugin } from "@dxos/plugin-preview/testing";
|
|
10
|
+
import { StorybookPlugin, corePlugins } from "@dxos/plugin-testing";
|
|
11
|
+
import { IndexKind } from "@dxos/react-client/echo";
|
|
12
|
+
import { withLayout } from "@dxos/react-ui/testing";
|
|
13
|
+
import { seedTestData } from "@dxos/types/testing";
|
|
14
|
+
import { IdentityDid } from "@dxos/keys";
|
|
15
|
+
import { random } from "@dxos/random";
|
|
16
|
+
//#region src/testing/testing.ts
|
|
17
|
+
var TestItem = Type.makeObject(DXN.make("org.dxos.type.test", "0.1.0"))(Schema.Struct({
|
|
18
|
+
title: Schema.String.annotations({
|
|
19
|
+
title: "Title",
|
|
20
|
+
description: "Product title"
|
|
21
|
+
}),
|
|
22
|
+
description: Schema.String.annotations({
|
|
23
|
+
title: "Description",
|
|
24
|
+
description: "Product description"
|
|
25
|
+
})
|
|
26
|
+
}));
|
|
27
|
+
var AbstractMessageBuilder = class {};
|
|
28
|
+
/**
|
|
29
|
+
* Generator of transcript messages.
|
|
30
|
+
*/
|
|
31
|
+
var MessageBuilder = class MessageBuilder extends AbstractMessageBuilder {
|
|
32
|
+
_space;
|
|
33
|
+
static singleton = new MessageBuilder();
|
|
34
|
+
users = Array.from({ length: 5 }, () => ({
|
|
35
|
+
identityDid: IdentityDid.random().toString(),
|
|
36
|
+
name: random.person.fullName(),
|
|
37
|
+
email: random.internet.email()
|
|
38
|
+
}));
|
|
39
|
+
start = /* @__PURE__ */ new Date(Date.now() - 1440 * 60 * 1e4);
|
|
40
|
+
constructor(_space) {
|
|
41
|
+
super();
|
|
42
|
+
this._space = _space;
|
|
43
|
+
}
|
|
44
|
+
async createMessage(numSegments = 1) {
|
|
45
|
+
return Obj.make(Message.Message, {
|
|
46
|
+
created: this.next().toISOString(),
|
|
47
|
+
sender: random.helpers.arrayElement(this.users),
|
|
48
|
+
blocks: Array.from({ length: numSegments }).map(() => this.createBlock())
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
createBlock() {
|
|
52
|
+
let text = random.lorem.paragraph();
|
|
53
|
+
if (this._space) {
|
|
54
|
+
const label = random.commerce.productName();
|
|
55
|
+
const obj = this._space.db.add(Obj.make(TestItem, {
|
|
56
|
+
title: label,
|
|
57
|
+
description: random.lorem.paragraph()
|
|
58
|
+
}));
|
|
59
|
+
const dxn = Ref.make(obj).uri;
|
|
60
|
+
const words = text.split(" ");
|
|
61
|
+
words.splice(Math.floor(Math.random() * words.length), 0, `[${label}](${dxn})`);
|
|
62
|
+
text = words.join(" ");
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
_tag: "transcript",
|
|
66
|
+
started: this.next().toISOString(),
|
|
67
|
+
text
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
next() {
|
|
71
|
+
this.start = new Date(this.start.getTime() + Math.random() * 1e4);
|
|
72
|
+
return this.start;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/testing/decorators.ts
|
|
77
|
+
var enableQueryIndexes = (services) => Effect.gen(function* () {
|
|
78
|
+
yield* Effect.promise(() => services.QueryService.setConfig({
|
|
79
|
+
enabled: true,
|
|
80
|
+
indexes: [
|
|
81
|
+
{ kind: IndexKind.Kind.SCHEMA_MATCH },
|
|
82
|
+
{ kind: IndexKind.Kind.GRAPH },
|
|
83
|
+
{ kind: IndexKind.Kind.VECTOR },
|
|
84
|
+
{ kind: IndexKind.Kind.FULL_TEXT }
|
|
85
|
+
]
|
|
86
|
+
}));
|
|
87
|
+
yield* Effect.promise(() => services.QueryService.reindex());
|
|
88
|
+
});
|
|
89
|
+
/**
|
|
90
|
+
* Standard plugin-manager decorator for transcription stories: core plugins, `ClientPlugin` with
|
|
91
|
+
* `Person`/`Organization`/`TestItem` schemas + seeded test data, plus `PreviewPlugin` and
|
|
92
|
+
* `TranscriptionPlugin`. Toggle `enableVectorIndex` for entity-extraction.
|
|
93
|
+
*/
|
|
94
|
+
var createStoryDecorators = ({ enableVectorIndex = false } = {}) => [withLayout({ layout: "column" }), withPluginManager({
|
|
95
|
+
plugins: [
|
|
96
|
+
...corePlugins(),
|
|
97
|
+
StorybookPlugin({}),
|
|
98
|
+
ClientPlugin({
|
|
99
|
+
types: [
|
|
100
|
+
TestItem,
|
|
101
|
+
Person.Person,
|
|
102
|
+
Organization.Organization
|
|
103
|
+
],
|
|
104
|
+
onClientInitialized: ({ client }) => Effect.gen(function* () {
|
|
105
|
+
const { personalSpace } = yield* initializeIdentity(client);
|
|
106
|
+
if (enableVectorIndex) yield* enableQueryIndexes(client.services.services);
|
|
107
|
+
yield* Effect.promise(() => seedTestData(personalSpace));
|
|
108
|
+
})
|
|
109
|
+
}),
|
|
110
|
+
PreviewPlugin(),
|
|
111
|
+
TranscriptionPlugin()
|
|
112
|
+
],
|
|
113
|
+
setupEvents: [AppActivationEvents.SetupSettings, AppActivationEvents.SetupAppGraph]
|
|
114
|
+
})];
|
|
115
|
+
//#endregion
|
|
116
|
+
export { MessageBuilder, TestItem, createStoryDecorators, enableQueryIndexes };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=testing.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"testing.mjs","names":[],"sources":["../../src/testing/testing.ts","../../src/testing/decorators.ts"],"sourcesContent":["//\n// Copyright 2025 DXOS.org\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { type Space } from '@dxos/client/echo';\nimport { DXN, Obj, Ref, Type } from '@dxos/echo';\nimport { IdentityDid } from '@dxos/keys';\nimport { random } from '@dxos/random';\nimport { type ContentBlock, Message } from '@dxos/types';\n\n// TODO(burdon): Reconcile with plugin-markdown. Move to @dxos/schema/testing.\nexport const TestItem = Type.makeObject(DXN.make('org.dxos.type.test', '0.1.0'))(\n Schema.Struct({\n title: Schema.String.annotations({\n title: 'Title',\n description: 'Product title',\n }),\n description: Schema.String.annotations({\n title: 'Description',\n description: 'Product description',\n }),\n }),\n);\n\n// TODO(wittjosiah): Make builder generic and reuse for all message types.\nabstract class AbstractMessageBuilder {\n abstract createMessage(numSegments?: number): Promise<Message.Message>;\n}\n\n/**\n * Generator of transcript messages.\n */\nexport class MessageBuilder extends AbstractMessageBuilder {\n static readonly singleton = new MessageBuilder();\n\n users = Array.from({ length: 5 }, () => ({\n identityDid: IdentityDid.random().toString(),\n name: random.person.fullName(),\n email: random.internet.email(),\n }));\n\n start = new Date(Date.now() - 24 * 60 * 60 * 10_000);\n\n constructor(private readonly _space?: Space) {\n super();\n }\n\n override async createMessage(numSegments = 1): Promise<Message.Message> {\n return Obj.make(Message.Message, {\n created: this.next().toISOString(),\n sender: random.helpers.arrayElement(this.users),\n blocks: Array.from({ length: numSegments }).map(() => this.createBlock()),\n });\n }\n\n createBlock(): ContentBlock.Transcript {\n let text = random.lorem.paragraph();\n if (this._space) {\n const label = random.commerce.productName();\n const obj = this._space.db.add(\n Obj.make(TestItem, {\n title: label,\n description: random.lorem.paragraph(),\n }),\n );\n const dxn = Ref.make(obj).uri;\n const words = text.split(' ');\n words.splice(Math.floor(Math.random() * words.length), 0, `[${label}](${dxn})`);\n text = words.join(' ');\n }\n\n return {\n _tag: 'transcript',\n started: this.next().toISOString(),\n text,\n };\n }\n\n next(): Date {\n this.start = new Date(this.start.getTime() + Math.random() * 10_000);\n return this.start;\n }\n}\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type Decorator } from '@storybook/react-vite';\nimport * as Effect from 'effect/Effect';\n\nimport { withPluginManager } from '@dxos/app-framework/testing';\nimport { AppActivationEvents } from '@dxos/app-toolkit';\nimport { ClientPlugin, initializeIdentity } from '@dxos/plugin-client/testing';\nimport { PreviewPlugin } from '@dxos/plugin-preview/testing';\nimport { StorybookPlugin, corePlugins } from '@dxos/plugin-testing';\nimport { IndexKind } from '@dxos/react-client/echo';\nimport { withLayout } from '@dxos/react-ui/testing';\nimport { Organization, Person } from '@dxos/types';\nimport { seedTestData } from '@dxos/types/testing';\n\nimport { TranscriptionPlugin } from '../TranscriptionPlugin';\nimport { TestItem } from './testing';\n\n// TODO(mykola): Make API easier to use.\n// TODO(mykola): Delete after enabling vector indexing by default.\nexport const enableQueryIndexes = (services: { QueryService?: any }) =>\n Effect.gen(function* () {\n yield* Effect.promise(() =>\n services.QueryService!.setConfig({\n enabled: true,\n indexes: [\n { kind: IndexKind.Kind.SCHEMA_MATCH },\n { kind: IndexKind.Kind.GRAPH },\n { kind: IndexKind.Kind.VECTOR },\n { kind: IndexKind.Kind.FULL_TEXT },\n ],\n }),\n );\n yield* Effect.promise(() => services.QueryService!.reindex());\n });\n\ntype StoryDecoratorsOptions = {\n /**\n * Enable schema/graph/vector indexes after the client boots; needed for entity-extraction\n * queries over seeded `Person` / `Organization` objects.\n * @default false\n */\n enableVectorIndex?: boolean;\n};\n\n/**\n * Standard plugin-manager decorator for transcription stories: core plugins, `ClientPlugin` with\n * `Person`/`Organization`/`TestItem` schemas + seeded test data, plus `PreviewPlugin` and\n * `TranscriptionPlugin`. Toggle `enableVectorIndex` for entity-extraction.\n */\nexport const createStoryDecorators = ({ enableVectorIndex = false }: StoryDecoratorsOptions = {}): Decorator[] => [\n withLayout({ layout: 'column' }),\n withPluginManager({\n plugins: [\n ...corePlugins(),\n StorybookPlugin({}),\n ClientPlugin({\n types: [TestItem, Person.Person, Organization.Organization],\n onClientInitialized: ({ client }) =>\n Effect.gen(function* () {\n const { personalSpace } = yield* initializeIdentity(client);\n if (enableVectorIndex) {\n yield* enableQueryIndexes(client.services.services);\n }\n yield* Effect.promise(() => seedTestData(personalSpace));\n }),\n }),\n PreviewPlugin(),\n TranscriptionPlugin(),\n ],\n // setupEvents (not fireEvents) so capabilities activate during app setup, before the always-mounted\n // driver renders: SetupSettings registers the session/settings/status capabilities it reads,\n // SetupAppGraph the graph + transcriber contributions.\n setupEvents: [AppActivationEvents.SetupSettings, AppActivationEvents.SetupAppGraph],\n }),\n];\n"],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { meta } from "#meta";
|
|
2
|
+
//#region src/translations.ts
|
|
3
|
+
var translations = [{ "en-US": { [meta.profile.key]: {
|
|
4
|
+
"plugin.name": "Transcription",
|
|
5
|
+
"transcript-companion.label": "Transcript",
|
|
6
|
+
"delete.button": "Delete",
|
|
7
|
+
"bookmark.button": "Bookmark",
|
|
8
|
+
"scroll-to-end.label": "Scroll to latest",
|
|
9
|
+
"start-recording.label": "Start recording",
|
|
10
|
+
"stop-recording.label": "Stop recording",
|
|
11
|
+
"hold-to-record.label": "Hold to record",
|
|
12
|
+
"recording-options.label": "Recording options",
|
|
13
|
+
"record-mode.label": "Record mode",
|
|
14
|
+
"record-mode.toggle.label": "Toggle",
|
|
15
|
+
"record-mode.hold.label": "Hold to record (push to talk)",
|
|
16
|
+
"audio-device.label": "Microphone",
|
|
17
|
+
"audio-device.default.label": "System default",
|
|
18
|
+
"settings.entity-extraction.label": "Entity extraction"
|
|
19
|
+
} } }];
|
|
20
|
+
//#endregion
|
|
21
|
+
export { translations };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=translations.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translations.mjs","names":[],"sources":["../../src/translations.ts"],"sourcesContent":["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Resource } from '@dxos/react-ui';\n\nimport { meta } from '#meta';\n\nexport const translations = [\n {\n 'en-US': {\n [meta.profile.key]: {\n 'plugin.name': 'Transcription',\n 'transcript-companion.label': 'Transcript',\n\n 'delete.button': 'Delete',\n 'bookmark.button': 'Bookmark',\n 'scroll-to-end.label': 'Scroll to latest',\n\n 'start-recording.label': 'Start recording',\n 'stop-recording.label': 'Stop recording',\n 'hold-to-record.label': 'Hold to record',\n\n 'recording-options.label': 'Recording options',\n 'record-mode.label': 'Record mode',\n 'record-mode.toggle.label': 'Toggle',\n 'record-mode.hold.label': 'Hold to record (push to talk)',\n 'audio-device.label': 'Microphone',\n 'audio-device.default.label': 'System default',\n\n 'settings.entity-extraction.label': 'Entity extraction',\n },\n },\n },\n] as const satisfies Resource[];\n"],"mappings":";;AAQA,IAAa,eAAe,CAC1B,EACE,SAAS,GACN,KAAK,QAAQ,MAAM;CAClB,eAAe;CACf,8BAA8B;CAE9B,iBAAiB;CACjB,mBAAmB;CACnB,uBAAuB;CAEvB,yBAAyB;CACzB,wBAAwB;CACxB,wBAAwB;CAExB,2BAA2B;CAC3B,qBAAqB;CACrB,4BAA4B;CAC5B,0BAA0B;CAC1B,sBAAsB;CACtB,8BAA8B;CAE9B,oCAAoC;AACtC,EACF,EACF,CACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { a as TranscriptOperation_exports, o as TranscriptionCapabilities_exports, s as Settings_exports } from "./chunk-types.mjs";
|
|
2
|
+
export { Settings_exports as Settings, TranscriptOperation_exports as TranscriptOperation, TranscriptionCapabilities_exports as TranscriptionCapabilities };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Effect from 'effect/Effect';
|
|
2
2
|
import { Capability } from '@dxos/app-framework';
|
|
3
|
-
declare const _default: (props: void) => Effect.Effect<Capability.Any, never,
|
|
3
|
+
declare const _default: (props: void) => Effect.Effect<Capability.Any, never, import("effect/Scope").Scope>;
|
|
4
4
|
export default _default;
|
|
5
5
|
//# sourceMappingURL=app-graph-builder.d.ts.map
|