@dxos/plugin-transcription 0.8.0 → 0.8.1-main.303c73a

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.
Files changed (74) hide show
  1. package/dist/lib/browser/{TranscriptContainer-SX6PNFEC.mjs → TranscriptContainer-N4KQHMY4.mjs} +2 -2
  2. package/dist/lib/browser/{chunk-AS364WZZ.mjs → chunk-BDVUIRBP.mjs} +2 -2
  3. package/dist/lib/browser/chunk-GHTRJTEB.mjs +35 -0
  4. package/dist/lib/browser/chunk-GHTRJTEB.mjs.map +7 -0
  5. package/dist/lib/browser/{chunk-R4HHS6FA.mjs → chunk-YX447BJ4.mjs} +16 -16
  6. package/dist/lib/browser/chunk-YX447BJ4.mjs.map +7 -0
  7. package/dist/lib/browser/index.mjs +180 -72
  8. package/dist/lib/browser/index.mjs.map +4 -4
  9. package/dist/lib/browser/{intent-resolver-EAR2TFK2.mjs → intent-resolver-RW6DEJC2.mjs} +2 -2
  10. package/dist/lib/browser/meta.json +1 -1
  11. package/dist/lib/browser/{react-surface-FOEWLLTZ.mjs → react-surface-UPTZBHVB.mjs} +3 -3
  12. package/dist/lib/node/{TranscriptContainer-HU763SN3.cjs → TranscriptContainer-4BWXOVML.cjs} +7 -7
  13. package/dist/lib/node/{TranscriptContainer-HU763SN3.cjs.map → TranscriptContainer-4BWXOVML.cjs.map} +2 -2
  14. package/dist/lib/node/{chunk-YV74Z74I.cjs → chunk-ANSWGFMS.cjs} +18 -18
  15. package/dist/lib/node/chunk-ANSWGFMS.cjs.map +7 -0
  16. package/dist/lib/node/{chunk-JBN3P6ZF.cjs → chunk-HDRXDMK2.cjs} +4 -46
  17. package/dist/lib/node/chunk-HDRXDMK2.cjs.map +7 -0
  18. package/dist/lib/node/{chunk-QWXLQPP5.cjs → chunk-I35KHI2G.cjs} +5 -5
  19. package/dist/lib/node/index.cjs +182 -74
  20. package/dist/lib/node/index.cjs.map +4 -4
  21. package/dist/lib/node/{intent-resolver-3KJZGGUQ.cjs → intent-resolver-KLBZ25XJ.cjs} +7 -7
  22. package/dist/lib/node/meta.json +1 -1
  23. package/dist/lib/node/{react-surface-AGGGDOUC.cjs → react-surface-NCKXB7EQ.cjs} +7 -7
  24. package/dist/lib/node-esm/{TranscriptContainer-DVBXQIQ4.mjs → TranscriptContainer-6IKRASR6.mjs} +2 -2
  25. package/dist/lib/node-esm/{chunk-WEZGRUG6.mjs → chunk-2CPKXRN6.mjs} +2 -2
  26. package/dist/lib/node-esm/chunk-LORUIVS4.mjs +37 -0
  27. package/dist/lib/node-esm/chunk-LORUIVS4.mjs.map +7 -0
  28. package/dist/lib/node-esm/{chunk-36EQXBWR.mjs → chunk-ZMK2QLW2.mjs} +16 -16
  29. package/dist/lib/node-esm/chunk-ZMK2QLW2.mjs.map +7 -0
  30. package/dist/lib/node-esm/index.mjs +180 -72
  31. package/dist/lib/node-esm/index.mjs.map +4 -4
  32. package/dist/lib/node-esm/{intent-resolver-UGLYRD4X.mjs → intent-resolver-4FMISUPW.mjs} +2 -2
  33. package/dist/lib/node-esm/meta.json +1 -1
  34. package/dist/lib/node-esm/{react-surface-6AYPLJ2B.mjs → react-surface-2WJQ67LB.mjs} +3 -3
  35. package/dist/types/src/capabilities/app-graph-builder.d.ts.map +1 -1
  36. package/dist/types/src/capabilities/index.d.ts.map +1 -1
  37. package/dist/types/src/components/transcription.stories.d.ts +2 -1
  38. package/dist/types/src/components/transcription.stories.d.ts.map +1 -1
  39. package/dist/types/src/hooks/index.d.ts +0 -1
  40. package/dist/types/src/hooks/index.d.ts.map +1 -1
  41. package/dist/types/src/index.d.ts +1 -0
  42. package/dist/types/src/index.d.ts.map +1 -1
  43. package/dist/types/src/transcriber/media-stream-recorder.d.ts +1 -0
  44. package/dist/types/src/transcriber/media-stream-recorder.d.ts.map +1 -1
  45. package/dist/types/src/transcription-manager.d.ts +36 -0
  46. package/dist/types/src/transcription-manager.d.ts.map +1 -0
  47. package/package.json +37 -37
  48. package/src/components/TranscriptContainer.tsx +11 -15
  49. package/src/hooks/index.ts +0 -1
  50. package/src/index.ts +1 -0
  51. package/src/transcriber/media-stream-recorder.ts +4 -0
  52. package/src/transcription-manager.ts +173 -0
  53. package/dist/lib/browser/chunk-R4HHS6FA.mjs.map +0 -7
  54. package/dist/lib/browser/chunk-ZMES3U2D.mjs +0 -78
  55. package/dist/lib/browser/chunk-ZMES3U2D.mjs.map +0 -7
  56. package/dist/lib/node/chunk-JBN3P6ZF.cjs.map +0 -7
  57. package/dist/lib/node/chunk-YV74Z74I.cjs.map +0 -7
  58. package/dist/lib/node-esm/chunk-36EQXBWR.mjs.map +0 -7
  59. package/dist/lib/node-esm/chunk-XYU6B73V.mjs +0 -80
  60. package/dist/lib/node-esm/chunk-XYU6B73V.mjs.map +0 -7
  61. package/dist/types/src/hooks/useIsSpeaking.d.ts +0 -2
  62. package/dist/types/src/hooks/useIsSpeaking.d.ts.map +0 -1
  63. package/src/hooks/useIsSpeaking.ts +0 -77
  64. /package/dist/lib/browser/{TranscriptContainer-SX6PNFEC.mjs.map → TranscriptContainer-N4KQHMY4.mjs.map} +0 -0
  65. /package/dist/lib/browser/{chunk-AS364WZZ.mjs.map → chunk-BDVUIRBP.mjs.map} +0 -0
  66. /package/dist/lib/browser/{intent-resolver-EAR2TFK2.mjs.map → intent-resolver-RW6DEJC2.mjs.map} +0 -0
  67. /package/dist/lib/browser/{react-surface-FOEWLLTZ.mjs.map → react-surface-UPTZBHVB.mjs.map} +0 -0
  68. /package/dist/lib/node/{chunk-QWXLQPP5.cjs.map → chunk-I35KHI2G.cjs.map} +0 -0
  69. /package/dist/lib/node/{intent-resolver-3KJZGGUQ.cjs.map → intent-resolver-KLBZ25XJ.cjs.map} +0 -0
  70. /package/dist/lib/node/{react-surface-AGGGDOUC.cjs.map → react-surface-NCKXB7EQ.cjs.map} +0 -0
  71. /package/dist/lib/node-esm/{TranscriptContainer-DVBXQIQ4.mjs.map → TranscriptContainer-6IKRASR6.mjs.map} +0 -0
  72. /package/dist/lib/node-esm/{chunk-WEZGRUG6.mjs.map → chunk-2CPKXRN6.mjs.map} +0 -0
  73. /package/dist/lib/node-esm/{intent-resolver-UGLYRD4X.mjs.map → intent-resolver-4FMISUPW.mjs.map} +0 -0
  74. /package/dist/lib/node-esm/{react-surface-6AYPLJ2B.mjs.map → react-surface-2WJQ67LB.mjs.map} +0 -0
@@ -9,7 +9,7 @@ import { pipe } from "effect";
9
9
  import React2, { useCallback, useMemo, useState } from "react";
10
10
  import { chain, createIntent, LayoutAction, useIntentDispatcher } from "@dxos/app-framework";
11
11
  import { Message } from "@dxos/artifact";
12
- import { AIServiceClientImpl, DEFAULT_LLM_MODEL, MixedStreamParser } from "@dxos/assistant";
12
+ import { AIServiceEdgeClient, DEFAULT_LLM_MODEL, MixedStreamParser } from "@dxos/assistant";
13
13
  import { create, getSpace, makeRef } from "@dxos/client/echo";
14
14
  import { QueueImpl } from "@dxos/echo-db";
15
15
  import { createStatic, isInstanceOf } from "@dxos/echo-schema";
@@ -82,7 +82,7 @@ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/plugins/experimental/pl
82
82
  var TranscriptionContainer = ({ transcript }) => {
83
83
  const { t } = useTranslation2(TRANSCRIPTION_PLUGIN);
84
84
  const edge = useEdgeClient();
85
- const aiService = useAiServiceClient();
85
+ const ai = useAiServiceClient();
86
86
  const { dispatchPromise: dispatch } = useIntentDispatcher();
87
87
  const queue = useQueue(edge, transcript.queue ? DXN.parse(transcript.queue) : void 0, {
88
88
  pollInterval: 1e3
@@ -91,7 +91,7 @@ var TranscriptionContainer = ({ transcript }) => {
91
91
  const handleSummarize = useCallback(async () => {
92
92
  setIsSummarizing(true);
93
93
  try {
94
- const document = await summarizeTranscript(edge, aiService, transcript);
94
+ const document = await summarizeTranscript(edge, ai, transcript);
95
95
  const space = getSpace(transcript);
96
96
  const target = space?.properties[CollectionType.typename]?.target;
97
97
  await dispatch(pipe(createIntent(SpaceAction.AddObject, {
@@ -125,17 +125,17 @@ var TranscriptionContainer = ({ transcript }) => {
125
125
  })));
126
126
  };
127
127
  var TranscriptContainer_default = TranscriptionContainer;
128
- var summarizeTranscript = async (edgeClient, aiService, transcript) => {
128
+ var summarizeTranscript = async (edge, ai, transcript) => {
129
129
  invariant(transcript.queue, "No queue found for transcript", {
130
130
  F: __dxlog_file,
131
- L: 90,
131
+ L: 86,
132
132
  S: void 0,
133
133
  A: [
134
134
  "transcript.queue",
135
135
  "'No queue found for transcript'"
136
136
  ]
137
137
  });
138
- const queue = new QueueImpl(edgeClient, DXN.parse(transcript.queue));
138
+ const queue = new QueueImpl(edge, DXN.parse(transcript.queue));
139
139
  await queue.refresh();
140
140
  const content = queue.items.filter((block) => isInstanceOf(TranscriptBlock, block)).map((block) => `${block.author}: ${block.segments.map((segment) => segment.text).join("\n")}`).join("\n\n");
141
141
  const parser = new MixedStreamParser();
@@ -143,11 +143,11 @@ var summarizeTranscript = async (edgeClient, aiService, transcript) => {
143
143
  blockCount: queue.items.length
144
144
  }, {
145
145
  F: __dxlog_file,
146
- L: 101,
146
+ L: 97,
147
147
  S: void 0,
148
148
  C: (f, a) => f(...a)
149
149
  });
150
- const output = await parser.parse(await aiService.exec({
150
+ const output = await parser.parse(await ai.exec({
151
151
  model: DEFAULT_LLM_MODEL,
152
152
  systemPrompt: SUMMARIZE_PROMPT,
153
153
  history: [
@@ -166,13 +166,13 @@ var summarizeTranscript = async (edgeClient, aiService, transcript) => {
166
166
  output
167
167
  }, {
168
168
  F: __dxlog_file,
169
- L: 110,
169
+ L: 106,
170
170
  S: void 0,
171
171
  C: (f, a) => f(...a)
172
172
  });
173
173
  invariant(output[0].content[0].type === "text", "Expected text content", {
174
174
  F: __dxlog_file,
175
- L: 111,
175
+ L: 107,
176
176
  S: void 0,
177
177
  A: [
178
178
  "output[0].content[0].type === 'text'",
@@ -212,10 +212,10 @@ var SUMMARIZE_PROMPT = `
212
212
  # Tasks
213
213
  At the end of the summary include tasks.
214
214
  Extract only the tasks that are:
215
- - Directly actionable
216
- - Clearly assigned to a person or team (or can easily be inferred)
217
- - Strongly implied by the conversation and/or user note (no speculative tasks)
218
- - Specific enough that someone reading them would know exactly what to do next
215
+ - Directly actionable.
216
+ - Clearly assigned to a person or team (or can easily be inferred).
217
+ - Strongly implied by the conversation and/or user note (no speculative tasks).
218
+ - Specific enough that someone reading them would know exactly what to do next.
219
219
 
220
220
  Format all tasks as markdown checkboxes using the syntax:
221
221
  - [ ] Task description
@@ -227,7 +227,7 @@ var SUMMARIZE_PROMPT = `
227
227
  var useAiServiceClient = () => {
228
228
  const config = useConfig();
229
229
  const endpoint = config.values.runtime?.services?.ai?.server ?? "http://localhost:8788";
230
- return useMemo(() => new AIServiceClientImpl({
230
+ return useMemo(() => new AIServiceEdgeClient({
231
231
  endpoint
232
232
  }), [
233
233
  endpoint
@@ -239,4 +239,4 @@ export {
239
239
  TranscriptionContainer,
240
240
  TranscriptContainer_default
241
241
  };
242
- //# sourceMappingURL=chunk-36EQXBWR.mjs.map
242
+ //# sourceMappingURL=chunk-ZMK2QLW2.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/components/TranscriptContainer.tsx", "../../../src/components/Transcript/Transcript.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { pipe } from 'effect';\nimport React, { useCallback, useMemo, useState, type FC } from 'react';\n\nimport { chain, createIntent, LayoutAction, useIntentDispatcher } from '@dxos/app-framework';\nimport { Message } from '@dxos/artifact';\nimport { AIServiceEdgeClient, DEFAULT_LLM_MODEL, MixedStreamParser, type AIServiceClient } from '@dxos/assistant';\nimport { create, getSpace, makeRef } from '@dxos/client/echo';\nimport { QueueImpl } from '@dxos/echo-db';\nimport { createStatic, isInstanceOf } from '@dxos/echo-schema';\nimport { invariant } from '@dxos/invariant';\nimport { DXN } from '@dxos/keys';\nimport { log } from '@dxos/log';\nimport { DocumentType } from '@dxos/plugin-markdown/types';\nimport { CollectionType, SpaceAction } from '@dxos/plugin-space/types';\nimport { useConfig } from '@dxos/react-client';\nimport { useEdgeClient, useQueue, type EdgeHttpClient } from '@dxos/react-edge-client';\nimport { IconButton, Toolbar, useTranslation } from '@dxos/react-ui';\nimport { ScrollContainer } from '@dxos/react-ui-components';\nimport { StackItem } from '@dxos/react-ui-stack';\nimport { TextType } from '@dxos/schema';\n\nimport { Transcript } from './Transcript';\nimport { TRANSCRIPTION_PLUGIN } from '../meta';\nimport { TranscriptBlock, type TranscriptType } from '../types';\n\nexport const TranscriptionContainer: FC<{ transcript: TranscriptType }> = ({ transcript }) => {\n const { t } = useTranslation(TRANSCRIPTION_PLUGIN);\n const edge = useEdgeClient();\n const ai = useAiServiceClient();\n const { dispatchPromise: dispatch } = useIntentDispatcher();\n\n const queue = useQueue<TranscriptBlock>(edge, transcript.queue ? DXN.parse(transcript.queue) : undefined, {\n pollInterval: 1_000,\n });\n\n // TODO(dmaretskyi): Pending state and errors should be handled by the framework!!!\n const [isSummarizing, setIsSummarizing] = useState(false);\n const handleSummarize = useCallback(async () => {\n setIsSummarizing(true);\n try {\n const document = await summarizeTranscript(edge, ai, transcript);\n const space = getSpace(transcript);\n const target = space?.properties[CollectionType.typename]?.target;\n await dispatch(\n pipe(\n createIntent(SpaceAction.AddObject, { object: document, target }),\n chain(LayoutAction.Open, { part: 'main' }),\n ),\n );\n } finally {\n setIsSummarizing(false);\n }\n }, [transcript, edge]);\n\n // TODO(dmaretskyi): Move action to menu.\n return (\n <StackItem.Content toolbar={true}>\n <StackItem.Heading>\n <Toolbar.Root classNames='flex gap-2'>\n <IconButton\n icon='ph--subtitles--regular'\n iconOnly\n size={5}\n disabled={isSummarizing}\n onClick={handleSummarize}\n label={t('summary button')}\n />\n {isSummarizing && <div className='text-sm'>{t('summarizing label')}</div>}\n </Toolbar.Root>\n </StackItem.Heading>\n <ScrollContainer>\n <Transcript blocks={queue?.items} />\n </ScrollContainer>\n </StackItem.Content>\n );\n};\n\nexport default TranscriptionContainer;\n\n// TODO(dmaretskyi): Extract to the new file once transcript refactoring has settled.\nconst summarizeTranscript = async (edge: EdgeHttpClient, ai: AIServiceClient, transcript: TranscriptType) => {\n invariant(transcript.queue, 'No queue found for transcript');\n\n const queue = new QueueImpl(edge, DXN.parse(transcript.queue));\n await queue.refresh();\n const content = queue.items\n .filter((block) => isInstanceOf(TranscriptBlock, block))\n .map((block) => `${block.author}: ${block.segments.map((segment) => segment.text).join('\\n')}`)\n .join('\\n\\n');\n\n const parser = new MixedStreamParser();\n\n log.info('summarizing transcript', { blockCount: queue.items.length });\n const output = await parser.parse(\n await ai.exec({\n model: DEFAULT_LLM_MODEL,\n systemPrompt: SUMMARIZE_PROMPT,\n history: [createStatic(Message, { role: 'user', content: [{ type: 'text', text: content }] })],\n }),\n );\n\n log.info('transcript summary', { output });\n invariant(output[0].content[0].type === 'text', 'Expected text content');\n const summary = output[0].content[0].text;\n\n // TODO(dmaretskyi): .started is missing.\n const name = `Summary ${(transcript.started ?? new Date()).toLocaleString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit',\n })}`;\n\n return create(DocumentType, {\n name,\n content: makeRef(create(TextType, { content: summary })),\n threads: [],\n });\n};\n\n// TODO(dmaretskyi): Add example to set consistent structure for the summary.\nconst SUMMARIZE_PROMPT = `\n # Goal\n Create a markdown summary of the transcript provided.\n\n # Formatting\n - Format the summary as a markdown document without extra comments like \"Here is the summary of the transcript:\".\n - Use markdown formatting for headings and bullet points.\n - Format the summary as a list of key points and takeaways.\n - All names of people should be in bold.\n\n # Note Taking\n - Correlate items in the summary with the person of origin to build a coherent narrative.\n - Include short quotes verbatim where appropriate. Especially when concerned with design decisions and problem descriptions.\n\n # Tasks\n At the end of the summary include tasks.\n Extract only the tasks that are:\n - Directly actionable.\n - Clearly assigned to a person or team (or can easily be inferred).\n - Strongly implied by the conversation and/or user note (no speculative tasks).\n - Specific enough that someone reading them would know exactly what to do next.\n\n Format all tasks as markdown checkboxes using the syntax:\n - [ ] Task description\n\n Additional information can be included (indented).\n\n If no actionable tasks are found, omit this tasks section.\n`;\n\n// TODO(dmaretskyi): Extract?\n// Also this conflicts with plugin automation providing the ai client via a capability. Need to reconcile.\nconst useAiServiceClient = (): AIServiceClient => {\n const config = useConfig();\n const endpoint = config.values.runtime?.services?.ai?.server ?? 'http://localhost:8788'; // TOOD(burdon): Standardize consts.\n return useMemo(() => new AIServiceEdgeClient({ endpoint }), [endpoint]);\n};\n", "//\n// Copyright 2023 DXOS.org\n//\n\nimport { formatDistanceToNow } from 'date-fns/formatDistanceToNow';\nimport React, { type FC } from 'react';\n\nimport { Icon, IconButton, useTranslation } from '@dxos/react-ui';\n\nimport { TRANSCRIPTION_PLUGIN } from '../../meta';\nimport { type TranscriptBlock } from '../../types';\n\n// TODO(burdon): react-ui-list.\n// TODO(burdon): Actions (e.g., mark, summarize, translate, label, delete).\n\nexport type TranscriptProps = {\n blocks?: TranscriptBlock[];\n};\n\nexport const Transcript: FC<TranscriptProps> = ({ blocks }) => {\n const { t } = useTranslation(TRANSCRIPTION_PLUGIN);\n const hoverButton = 'p-1 min-bs-1 transition-opacity duration-250 opacity-10 group-hover:opacity-100';\n\n return (\n <div role='list' className='flex flex-col grow gap-2 m-1'>\n {blocks?.map((block) => (\n <div\n role='listitem'\n key={block.id}\n className='flex flex-col py-1 border border-transparent hover:border-separator rounded'\n >\n <div className='group flex items-center px-2'>\n <Icon icon='ph--user--regular' />\n <div className='px-2 text-sm text-subdued'>{block.author}</div>\n <div className='grow' />\n <IconButton\n disabled\n icon='ph--x--regular'\n label={t('delete button')}\n iconOnly\n size={4}\n classNames={hoverButton}\n />\n </div>\n\n {block.segments.map((segment, i) => (\n <div key={i} className='group flex flex-col'>\n <div className='px-2'>{segment.text}</div>\n <div className='flex gap-1 items-center justify-between px-2'>\n <div className='grow' />\n <div className='truncate text-xs text-subdued'>\n {formatDistanceToNow(segment.started, { addSuffix: true })}\n </div>\n <IconButton\n disabled\n icon='ph--bookmark-simple--regular'\n label={t('bookmark button')}\n iconOnly\n size={4}\n classNames={hoverButton}\n />\n </div>\n </div>\n ))}\n </div>\n ))}\n </div>\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["pipe", "React", "useCallback", "useMemo", "useState", "chain", "createIntent", "LayoutAction", "useIntentDispatcher", "Message", "AIServiceEdgeClient", "DEFAULT_LLM_MODEL", "MixedStreamParser", "create", "getSpace", "makeRef", "QueueImpl", "createStatic", "isInstanceOf", "invariant", "DXN", "log", "DocumentType", "CollectionType", "SpaceAction", "useConfig", "useEdgeClient", "useQueue", "IconButton", "Toolbar", "useTranslation", "ScrollContainer", "StackItem", "TextType", "formatDistanceToNow", "React", "Icon", "IconButton", "useTranslation", "Transcript", "blocks", "t", "useTranslation", "TRANSCRIPTION_PLUGIN", "hoverButton", "div", "role", "className", "map", "block", "key", "id", "Icon", "icon", "author", "IconButton", "disabled", "label", "iconOnly", "size", "classNames", "segments", "segment", "i", "text", "formatDistanceToNow", "started", "addSuffix", "TranscriptionContainer", "transcript", "t", "useTranslation", "TRANSCRIPTION_PLUGIN", "edge", "useEdgeClient", "ai", "useAiServiceClient", "dispatchPromise", "dispatch", "useIntentDispatcher", "queue", "useQueue", "DXN", "parse", "undefined", "pollInterval", "isSummarizing", "setIsSummarizing", "useState", "handleSummarize", "useCallback", "document", "summarizeTranscript", "space", "getSpace", "target", "properties", "CollectionType", "typename", "pipe", "createIntent", "SpaceAction", "AddObject", "object", "chain", "LayoutAction", "Open", "part", "React", "StackItem", "Content", "toolbar", "Heading", "Toolbar", "Root", "classNames", "IconButton", "icon", "iconOnly", "size", "disabled", "onClick", "label", "div", "className", "ScrollContainer", "Transcript", "blocks", "items", "invariant", "QueueImpl", "refresh", "content", "filter", "block", "isInstanceOf", "TranscriptBlock", "map", "author", "segments", "segment", "text", "join", "parser", "MixedStreamParser", "log", "info", "blockCount", "length", "output", "exec", "model", "DEFAULT_LLM_MODEL", "systemPrompt", "SUMMARIZE_PROMPT", "history", "createStatic", "Message", "role", "type", "summary", "name", "started", "Date", "toLocaleString", "year", "month", "day", "hour", "minute", "create", "DocumentType", "makeRef", "TextType", "threads", "config", "useConfig", "endpoint", "values", "runtime", "services", "server", "useMemo", "AIServiceEdgeClient"]
7
+ }
@@ -1,18 +1,18 @@
1
1
  import { createRequire } from 'node:module';const require = createRequire(import.meta.url);
2
2
  import {
3
- mergeFloat64Arrays,
4
- monitorAudioLevel
5
- } from "./chunk-XYU6B73V.mjs";
3
+ mergeFloat64Arrays
4
+ } from "./chunk-LORUIVS4.mjs";
6
5
  import {
7
6
  TranscriptContainer
8
- } from "./chunk-WEZGRUG6.mjs";
7
+ } from "./chunk-2CPKXRN6.mjs";
9
8
  import {
10
9
  Transcript,
11
10
  TranscriptionContainer
12
- } from "./chunk-36EQXBWR.mjs";
11
+ } from "./chunk-ZMK2QLW2.mjs";
13
12
  import {
14
13
  TRANSCRIPTION_PLUGIN,
15
14
  TRANSCRIPTION_URL,
15
+ TranscriptBlock,
16
16
  TranscriptType,
17
17
  meta
18
18
  } from "./chunk-KEG3ME4O.mjs";
@@ -29,8 +29,8 @@ var TranscriptionCapabilities;
29
29
 
30
30
  // packages/plugins/experimental/plugin-transcription/src/capabilities/index.ts
31
31
  var AppGraphBuilder = lazy(() => import("./app-graph-builder-77GQG6UF.mjs"));
32
- var IntentResolver = lazy(() => import("./intent-resolver-UGLYRD4X.mjs"));
33
- var ReactSurface = lazy(() => import("./react-surface-6AYPLJ2B.mjs"));
32
+ var IntentResolver = lazy(() => import("./intent-resolver-4FMISUPW.mjs"));
33
+ var ReactSurface = lazy(() => import("./react-surface-2WJQ67LB.mjs"));
34
34
 
35
35
  // packages/plugins/experimental/plugin-transcription/src/hooks/useAudioFile.ts
36
36
  import { useEffect, useState } from "react";
@@ -122,64 +122,8 @@ var useAudioTrack = (active) => {
122
122
  return track;
123
123
  };
124
124
 
125
- // packages/plugins/experimental/plugin-transcription/src/hooks/useIsSpeaking.ts
126
- import { useEffect as useEffect3, useRef, useState as useState3 } from "react";
127
- var useIsSpeaking = (mediaStreamTrack) => {
128
- const [isSpeaking, setIsSpeaking] = useState3(false);
129
- const isSpeakingRef = useRef(isSpeaking);
130
- useEffect3(() => {
131
- if (!mediaStreamTrack) {
132
- setIsSpeaking(false);
133
- return;
134
- }
135
- isSpeakingRef.current = isSpeaking;
136
- const interval = window.setInterval(() => {
137
- if (isSpeaking === isSpeakingRef.current) {
138
- return;
139
- }
140
- setIsSpeaking(isSpeakingRef.current);
141
- }, 50);
142
- return () => {
143
- clearInterval(interval);
144
- };
145
- }, [
146
- isSpeaking,
147
- isSpeakingRef,
148
- mediaStreamTrack
149
- ]);
150
- useEffect3(() => {
151
- if (!mediaStreamTrack) {
152
- return;
153
- }
154
- let timeout = -1;
155
- const cleanup = monitorAudioLevel({
156
- mediaStreamTrack,
157
- onMeasure: (vol) => {
158
- const audioLevelAboveThreshold = vol > (isSpeakingRef.current ? 0.02 : 0.05);
159
- if (audioLevelAboveThreshold) {
160
- clearTimeout(timeout);
161
- timeout = -1;
162
- isSpeakingRef.current = true;
163
- } else if (timeout === -1) {
164
- timeout = window.setTimeout(() => {
165
- isSpeakingRef.current = false;
166
- timeout = -1;
167
- }, 1e3);
168
- }
169
- }
170
- });
171
- return () => {
172
- cleanup();
173
- };
174
- }, [
175
- isSpeaking,
176
- mediaStreamTrack
177
- ]);
178
- return isSpeaking;
179
- };
180
-
181
125
  // packages/plugins/experimental/plugin-transcription/src/hooks/useTranscriber.ts
182
- import { useEffect as useEffect4, useMemo } from "react";
126
+ import { useEffect as useEffect3, useMemo } from "react";
183
127
 
184
128
  // packages/plugins/experimental/plugin-transcription/src/transcriber/media-stream-recorder.ts
185
129
  import { MediaRecorder, register } from "extendable-media-recorder";
@@ -215,6 +159,9 @@ var MediaStreamRecorder = class {
215
159
  bitDepthCode: settings.sampleSize ? String(settings.sampleSize) : "16"
216
160
  };
217
161
  }
162
+ get mediaStreamTrack() {
163
+ return this._mediaStreamTrack;
164
+ }
218
165
  setOnChunk(onChunk) {
219
166
  this._onChunk = onChunk;
220
167
  }
@@ -223,7 +170,7 @@ var MediaStreamRecorder = class {
223
170
  err
224
171
  }, {
225
172
  F: __dxlog_file2,
226
- L: 58,
173
+ L: 62,
227
174
  S: this,
228
175
  C: (f, a) => f(...a)
229
176
  }));
@@ -240,7 +187,7 @@ var MediaStreamRecorder = class {
240
187
  }
241
188
  invariant(this._onChunk, "MediaStreamRecorder: onChunk is not set", {
242
189
  F: __dxlog_file2,
243
- L: 69,
190
+ L: 73,
244
191
  S: this,
245
192
  A: [
246
193
  "this._onChunk",
@@ -275,7 +222,7 @@ var MediaStreamRecorder = class {
275
222
  } else {
276
223
  log2.warn("MediaStreamRecorder: no header", void 0, {
277
224
  F: __dxlog_file2,
278
- L: 100,
225
+ L: 104,
279
226
  S: this,
280
227
  C: (f, a) => f(...a)
281
228
  });
@@ -480,7 +427,7 @@ var useTranscriber = ({ audioStreamTrack, onSegments }) => {
480
427
  audioStreamTrack,
481
428
  onSegments
482
429
  ]);
483
- useEffect4(() => {
430
+ useEffect3(() => {
484
431
  return () => {
485
432
  void transcriber?.close();
486
433
  };
@@ -491,7 +438,7 @@ var useTranscriber = ({ audioStreamTrack, onSegments }) => {
491
438
  };
492
439
 
493
440
  // packages/plugins/experimental/plugin-transcription/src/hooks/useVoiceInput.ts
494
- import { useState as useState4, useEffect as useEffect5, useCallback } from "react";
441
+ import { useState as useState3, useEffect as useEffect4, useCallback } from "react";
495
442
  import { scheduleMicroTask } from "@dxos/async";
496
443
  import { Context } from "@dxos/context";
497
444
  import { log as log4 } from "@dxos/log";
@@ -504,13 +451,13 @@ var useVoiceInput = ({ active, onUpdate }) => {
504
451
  const text = segments.map((str) => str.text.trim().replace(/[^\w\s]/g, "")).join(" ");
505
452
  onUpdate(text);
506
453
  }, []);
507
- const [recording, setRecording] = useState4(false);
454
+ const [recording, setRecording] = useState3(false);
508
455
  const track = useAudioTrack(active);
509
456
  const transcriber = useTranscriber({
510
457
  audioStreamTrack: track,
511
458
  onSegments: handleSegments
512
459
  });
513
- useEffect5(() => {
460
+ useEffect4(() => {
514
461
  const ctx = new Context(void 0, {
515
462
  F: __dxlog_file4,
516
463
  L: 43
@@ -552,6 +499,167 @@ var useVoiceInput = ({ active, onUpdate }) => {
552
499
  };
553
500
  };
554
501
 
502
+ // packages/plugins/experimental/plugin-transcription/src/transcription-manager.ts
503
+ import { synchronized as synchronized2 } from "@dxos/async";
504
+ import { Resource as Resource2 } from "@dxos/context";
505
+ import { QueueImpl } from "@dxos/echo-db";
506
+ import { createStatic } from "@dxos/echo-schema";
507
+ import { invariant as invariant2 } from "@dxos/invariant";
508
+ import { DXN } from "@dxos/keys";
509
+ function _ts_decorate3(decorators, target, key, desc) {
510
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
511
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
512
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
513
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
514
+ }
515
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/plugins/experimental/plugin-transcription/src/transcription-manager.ts";
516
+ var RECORD_INTERVAL2 = 200;
517
+ var PREFIXED_CHUNKS_AMOUNT2 = 10;
518
+ var TRANSCRIBE_AFTER_CHUNKS_AMOUNT2 = 50;
519
+ var TranscriptionManager = class extends Resource2 {
520
+ constructor(edgeClient) {
521
+ super();
522
+ this._audioStreamTrack = void 0;
523
+ this._name = void 0;
524
+ this._mediaRecorder = void 0;
525
+ this._transcriber = void 0;
526
+ this._enabled = false;
527
+ this._queue = void 0;
528
+ this._edgeClient = edgeClient;
529
+ }
530
+ async _open() {
531
+ await this._toggleTranscriber();
532
+ }
533
+ async _close() {
534
+ void this._transcriber?.close();
535
+ }
536
+ setRecording(recording) {
537
+ if (!this.isOpen || !this._enabled) {
538
+ return;
539
+ }
540
+ if (recording) {
541
+ this._transcriber?.startChunksRecording();
542
+ } else {
543
+ this._transcriber?.stopChunksRecording();
544
+ }
545
+ }
546
+ /**
547
+ * Enable or disable transcription.
548
+ * @param enabled - Whether to enable transcription.
549
+ */
550
+ async setEnabled(enabled) {
551
+ if (this._enabled === enabled) {
552
+ return;
553
+ }
554
+ this._enabled = enabled ?? false;
555
+ this.isOpen && await this._toggleTranscriber();
556
+ }
557
+ async setAudioTrack(track) {
558
+ if (this._audioStreamTrack === track) {
559
+ return;
560
+ }
561
+ this._audioStreamTrack = track;
562
+ this.isOpen && await this._toggleTranscriber();
563
+ }
564
+ /**
565
+ * Set the queue to save the transcription to.
566
+ * @param queue - The queue to save the transcription to or the DXN of the queue.
567
+ */
568
+ setQueue(queue) {
569
+ switch (typeof queue) {
570
+ case "string":
571
+ if (this._queue?.dxn.toString() === queue) {
572
+ return;
573
+ }
574
+ this._queue = new QueueImpl(this._edgeClient, DXN.parse(queue));
575
+ break;
576
+ case "object":
577
+ if (this._queue === queue) {
578
+ return;
579
+ }
580
+ invariant2(queue instanceof QueueImpl, void 0, {
581
+ F: __dxlog_file5,
582
+ L: 110,
583
+ S: this,
584
+ A: [
585
+ "queue instanceof QueueImpl",
586
+ ""
587
+ ]
588
+ });
589
+ this._queue = queue;
590
+ break;
591
+ case "undefined":
592
+ this._queue = void 0;
593
+ break;
594
+ }
595
+ }
596
+ setName(name) {
597
+ if (this._name === name) {
598
+ return;
599
+ }
600
+ this._name = name;
601
+ }
602
+ async _toggleTranscriber() {
603
+ await this._maybeReinitTranscriber();
604
+ if (this._enabled) {
605
+ await this._transcriber?.open();
606
+ } else {
607
+ await this._transcriber?.close();
608
+ }
609
+ }
610
+ async _maybeReinitTranscriber() {
611
+ if (!this._audioStreamTrack || !this._enabled) {
612
+ return;
613
+ }
614
+ let needReinit = false;
615
+ if (this._audioStreamTrack !== this._mediaRecorder?.mediaStreamTrack) {
616
+ this._mediaRecorder = new MediaStreamRecorder({
617
+ mediaStreamTrack: this._audioStreamTrack,
618
+ interval: RECORD_INTERVAL2
619
+ });
620
+ needReinit = true;
621
+ }
622
+ if (needReinit) {
623
+ await this._transcriber?.close();
624
+ this._transcriber = new Transcriber({
625
+ config: {
626
+ transcribeAfterChunksAmount: TRANSCRIBE_AFTER_CHUNKS_AMOUNT2,
627
+ prefixBufferChunksAmount: PREFIXED_CHUNKS_AMOUNT2
628
+ },
629
+ recorder: this._mediaRecorder,
630
+ onSegments: (segments) => this._onSegments(segments)
631
+ });
632
+ }
633
+ }
634
+ async _onSegments(segments) {
635
+ if (!this.isOpen || !this._queue) {
636
+ return;
637
+ }
638
+ const block = createStatic(TranscriptBlock, {
639
+ author: this._name,
640
+ segments
641
+ });
642
+ this._queue.append([
643
+ block
644
+ ]);
645
+ }
646
+ };
647
+ _ts_decorate3([
648
+ synchronized2
649
+ ], TranscriptionManager.prototype, "setRecording", null);
650
+ _ts_decorate3([
651
+ synchronized2
652
+ ], TranscriptionManager.prototype, "setEnabled", null);
653
+ _ts_decorate3([
654
+ synchronized2
655
+ ], TranscriptionManager.prototype, "setAudioTrack", null);
656
+ _ts_decorate3([
657
+ synchronized2
658
+ ], TranscriptionManager.prototype, "setQueue", null);
659
+ _ts_decorate3([
660
+ synchronized2
661
+ ], TranscriptionManager.prototype, "setName", null);
662
+
555
663
  // packages/plugins/experimental/plugin-transcription/src/TranscriptionPlugin.tsx
556
664
  import { Capabilities, Events, contributes, defineModule, definePlugin } from "@dxos/app-framework";
557
665
  import { ClientCapabilities, ClientEvents } from "@dxos/plugin-client";
@@ -642,11 +750,11 @@ export {
642
750
  TranscriptContainer,
643
751
  TranscriptionCapabilities,
644
752
  TranscriptionContainer,
753
+ TranscriptionManager,
645
754
  TranscriptionPlugin,
646
755
  meta,
647
756
  useAudioFile,
648
757
  useAudioTrack,
649
- useIsSpeaking,
650
758
  useTranscriber,
651
759
  useVoiceInput
652
760
  };