@dxos/plugin-transformer 0.8.4-main.dedc0f3 → 0.8.4-main.dfabb4ec29

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 (75) hide show
  1. package/dist/lib/neutral/TransformerPlugin.mjs +25 -0
  2. package/dist/lib/neutral/TransformerPlugin.mjs.map +7 -0
  3. package/dist/lib/neutral/chunk-BKDV4JXC.mjs +20 -0
  4. package/dist/lib/neutral/chunk-BKDV4JXC.mjs.map +7 -0
  5. package/dist/lib/neutral/components/index.mjs +136 -0
  6. package/dist/lib/neutral/components/index.mjs.map +7 -0
  7. package/dist/lib/neutral/hooks/index.mjs +339 -0
  8. package/dist/lib/neutral/hooks/index.mjs.map +7 -0
  9. package/dist/lib/neutral/index.mjs +7 -0
  10. package/dist/lib/neutral/meta.json +1 -0
  11. package/dist/lib/neutral/meta.mjs +7 -0
  12. package/dist/lib/neutral/plugin.mjs +11 -0
  13. package/dist/lib/neutral/plugin.mjs.map +7 -0
  14. package/dist/lib/neutral/translations.mjs +15 -0
  15. package/dist/lib/neutral/translations.mjs.map +7 -0
  16. package/dist/types/src/TransformerPlugin.d.ts +3 -1
  17. package/dist/types/src/TransformerPlugin.d.ts.map +1 -1
  18. package/dist/types/src/TransformerPlugin.test.d.ts +2 -0
  19. package/dist/types/src/TransformerPlugin.test.d.ts.map +1 -0
  20. package/dist/types/src/components/Voice/DebugInfo.d.ts.map +1 -0
  21. package/dist/types/src/components/Voice/Voice.d.ts.map +1 -0
  22. package/dist/types/src/components/{Voice.stories.d.ts → Voice/Voice.stories.d.ts} +0 -1
  23. package/dist/types/src/components/Voice/Voice.stories.d.ts.map +1 -0
  24. package/dist/types/src/components/Voice/index.d.ts +3 -0
  25. package/dist/types/src/components/Voice/index.d.ts.map +1 -0
  26. package/dist/types/src/components/index.d.ts +2 -0
  27. package/dist/types/src/components/index.d.ts.map +1 -0
  28. package/dist/types/src/hooks/useAudioStream.d.ts.map +1 -1
  29. package/dist/types/src/hooks/usePipeline.d.ts +1 -16
  30. package/dist/types/src/hooks/usePipeline.d.ts.map +1 -1
  31. package/dist/types/src/index.d.ts +0 -1
  32. package/dist/types/src/index.d.ts.map +1 -1
  33. package/dist/types/src/meta.d.ts +2 -3
  34. package/dist/types/src/meta.d.ts.map +1 -1
  35. package/dist/types/src/plugin.d.ts +3 -0
  36. package/dist/types/src/plugin.d.ts.map +1 -0
  37. package/dist/types/src/testing/node-pipeline.d.ts +1 -1
  38. package/dist/types/src/testing/node-pipeline.d.ts.map +1 -1
  39. package/dist/types/src/testing/pipeline.d.ts.map +1 -1
  40. package/dist/types/src/testing/web-pipeline.d.ts +1 -1
  41. package/dist/types/src/testing/web-pipeline.d.ts.map +1 -1
  42. package/dist/types/src/translations.d.ts +2 -3
  43. package/dist/types/src/translations.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +76 -50
  46. package/src/TransformerPlugin.test.ts +25 -0
  47. package/src/TransformerPlugin.tsx +16 -27
  48. package/src/components/{DebugInfo.tsx → Voice/DebugInfo.tsx} +3 -3
  49. package/src/components/{Voice.stories.tsx → Voice/Voice.stories.tsx} +3 -5
  50. package/src/components/{Voice.tsx → Voice/Voice.tsx} +1 -1
  51. package/src/components/Voice/index.ts +6 -0
  52. package/src/{capabilities → components}/index.ts +2 -0
  53. package/src/hooks/useAudioStream.ts +1 -1
  54. package/src/hooks/usePipeline.ts +9 -33
  55. package/src/index.ts +0 -2
  56. package/src/meta.ts +8 -6
  57. package/src/plugin.ts +9 -0
  58. package/src/translations.ts +2 -2
  59. package/dist/lib/browser/index.mjs +0 -52
  60. package/dist/lib/browser/index.mjs.map +0 -7
  61. package/dist/lib/browser/meta.json +0 -1
  62. package/dist/lib/browser/types/index.mjs +0 -1
  63. package/dist/lib/node-esm/index.mjs +0 -54
  64. package/dist/lib/node-esm/index.mjs.map +0 -7
  65. package/dist/lib/node-esm/meta.json +0 -1
  66. package/dist/lib/node-esm/types/index.mjs +0 -2
  67. package/dist/types/src/capabilities/index.d.ts +0 -1
  68. package/dist/types/src/capabilities/index.d.ts.map +0 -1
  69. package/dist/types/src/components/DebugInfo.d.ts.map +0 -1
  70. package/dist/types/src/components/Voice.d.ts.map +0 -1
  71. package/dist/types/src/components/Voice.stories.d.ts.map +0 -1
  72. /package/dist/lib/{browser/types → neutral}/index.mjs.map +0 -0
  73. /package/dist/lib/{node-esm/types/index.mjs.map → neutral/meta.mjs.map} +0 -0
  74. /package/dist/types/src/components/{DebugInfo.d.ts → Voice/DebugInfo.d.ts} +0 -0
  75. /package/dist/types/src/components/{Voice.d.ts → Voice/Voice.d.ts} +0 -0
@@ -0,0 +1,25 @@
1
+ // src/TransformerPlugin.tsx
2
+ import { Plugin } from "@dxos/app-framework";
3
+ import { AppPlugin } from "@dxos/app-toolkit";
4
+ import { meta } from "#meta";
5
+ import { translations } from "#translations";
6
+ var TransformerPlugin = Plugin.define(meta).pipe(
7
+ AppPlugin.addSchemaModule({
8
+ schema: []
9
+ }),
10
+ AppPlugin.addTranslationsModule({
11
+ translations
12
+ }),
13
+ // Plugin.addModule({
14
+ // id: 'intent-resolver',
15
+ // activatesOn: Events.SetupIntentResolver,
16
+ // activate: IntentResolver,
17
+ // }),
18
+ Plugin.make
19
+ );
20
+ var TransformerPlugin_default = TransformerPlugin;
21
+ export {
22
+ TransformerPlugin,
23
+ TransformerPlugin_default as default
24
+ };
25
+ //# sourceMappingURL=TransformerPlugin.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/TransformerPlugin.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { Plugin } from '@dxos/app-framework';\nimport { AppPlugin } from '@dxos/app-toolkit';\n\n// import { IntentResolver } from './capabilities';\nimport { meta } from '#meta';\nimport { translations } from '#translations';\n\nexport const TransformerPlugin = Plugin.define(meta).pipe(\n AppPlugin.addSchemaModule({ schema: [] }),\n AppPlugin.addTranslationsModule({ translations }),\n // Plugin.addModule({\n // id: 'intent-resolver',\n // activatesOn: Events.SetupIntentResolver,\n // activate: IntentResolver,\n // }),\n Plugin.make,\n);\n\nexport default TransformerPlugin;\n"],
5
+ "mappings": ";AAIA,SAASA,cAAc;AACvB,SAASC,iBAAiB;AAG1B,SAASC,YAAY;AACrB,SAASC,oBAAoB;AAEtB,IAAMC,oBAAoBJ,OAAOK,OAAOH,IAAAA,EAAMI;EACnDL,UAAUM,gBAAgB;IAAEC,QAAQ,CAAA;EAAG,CAAA;EACvCP,UAAUQ,sBAAsB;IAAEN;EAAa,CAAA;;;;;;EAM/CH,OAAOU;AAAI;AAGb,IAAA,4BAAeN;",
6
+ "names": ["Plugin", "AppPlugin", "meta", "translations", "TransformerPlugin", "define", "pipe", "addSchemaModule", "schema", "addTranslationsModule", "make"]
7
+ }
@@ -0,0 +1,20 @@
1
+ // src/meta.ts
2
+ import { trim } from "@dxos/util";
3
+ var meta = {
4
+ id: "org.dxos.plugin.transformer",
5
+ name: "Transformer",
6
+ description: trim`
7
+ Execute local machine learning transformers and AI models directly in your browser.
8
+ Run embeddings, classifications, and other ML tasks without server dependencies.
9
+ `,
10
+ icon: "ph--cpu--regular",
11
+ source: "https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-transformer",
12
+ tags: [
13
+ "labs"
14
+ ]
15
+ };
16
+
17
+ export {
18
+ meta
19
+ };
20
+ //# sourceMappingURL=chunk-BKDV4JXC.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/meta.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2023 DXOS.org\n//\n\nimport { type Plugin } from '@dxos/app-framework';\nimport { trim } from '@dxos/util';\n\nexport const meta: Plugin.Meta = {\n id: 'org.dxos.plugin.transformer',\n name: 'Transformer',\n description: trim`\n Execute local machine learning transformers and AI models directly in your browser.\n Run embeddings, classifications, and other ML tasks without server dependencies.\n `,\n icon: 'ph--cpu--regular',\n source: 'https://github.com/dxos/dxos/tree/main/packages/plugins/plugin-transformer',\n tags: ['labs'],\n};\n"],
5
+ "mappings": ";AAKA,SAASA,YAAY;AAEd,IAAMC,OAAoB;EAC/BC,IAAI;EACJC,MAAM;EACNC,aAAaJ;;;;EAIbK,MAAM;EACNC,QAAQ;EACRC,MAAM;IAAC;;AACT;",
6
+ "names": ["trim", "meta", "id", "name", "description", "icon", "source", "tags"]
7
+ }
@@ -0,0 +1,136 @@
1
+ // src/components/Voice/DebugInfo.tsx
2
+ import React from "react";
3
+ var DebugInfo = ({ error, isModelLoading, stream, isTranscribing, transcription, audioLevel, gpuInfo, model, debug = false }) => {
4
+ return /* @__PURE__ */ React.createElement("div", {
5
+ className: "p-4"
6
+ }, error && /* @__PURE__ */ React.createElement("div", {
7
+ className: "mb-4 text-red-600"
8
+ }, /* @__PURE__ */ React.createElement("strong", null, "Error:"), " ", error), isModelLoading && /* @__PURE__ */ React.createElement("div", {
9
+ className: "mb-4"
10
+ }, /* @__PURE__ */ React.createElement("div", null, "Loading model..."), /* @__PURE__ */ React.createElement("div", {
11
+ className: "text-sm text-gray-500"
12
+ }, "This may take a few moments")), stream ? /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", {
13
+ className: "mb-2 text-green-600"
14
+ }, /* @__PURE__ */ React.createElement("strong", null, "Status:"), " Microphone is active", debug && audioLevel && /* @__PURE__ */ React.createElement("div", {
15
+ className: "mt-2 w-48 h-5 bg-gray-200 rounded-sm relative"
16
+ }, /* @__PURE__ */ React.createElement("div", {
17
+ className: "h-full bg-green-500 transition-all duration-100 rounded-sm",
18
+ style: {
19
+ width: `${audioLevel / 255 * 100}%`
20
+ }
21
+ }))), isTranscribing && /* @__PURE__ */ React.createElement("div", {
22
+ className: "mb-2 text-gray-500"
23
+ }, "Processing audio..."), debug && /* @__PURE__ */ React.createElement("div", {
24
+ className: "mb-4 text-sm text-gray-500 space-y-1"
25
+ }, /* @__PURE__ */ React.createElement("div", null, "Model: ", model), /* @__PURE__ */ React.createElement("div", null, "Sample Rate: 16000 Hz"), /* @__PURE__ */ React.createElement("div", null, "Format: audio/wav"), /* @__PURE__ */ React.createElement("div", null, "Chunk Size: 10 seconds"), /* @__PURE__ */ React.createElement("div", null, "GPU: ", gpuInfo || "Not available"), /* @__PURE__ */ React.createElement("div", null, "Backend: WebGPU")), transcription && /* @__PURE__ */ React.createElement("div", {
26
+ className: "mt-4"
27
+ }, /* @__PURE__ */ React.createElement("strong", null, "Transcription:"), /* @__PURE__ */ React.createElement("p", {
28
+ className: "mt-2 p-4 bg-gray-100 rounded-sm whitespace-pre-wrap"
29
+ }, transcription))) : /* @__PURE__ */ React.createElement("div", null, !isModelLoading && !error && /* @__PURE__ */ React.createElement("div", {
30
+ className: "text-gray-500"
31
+ }, "Microphone is inactive")));
32
+ };
33
+
34
+ // src/components/Voice/Voice.tsx
35
+ import React2, { useCallback, useEffect, useState } from "react";
36
+ import { log } from "@dxos/log";
37
+ import { useAudioStream, usePipeline } from "#hooks";
38
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transformer/src/components/Voice/Voice.tsx";
39
+ var Voice = ({ active, debug, model = "Xenova/whisper-base" }) => {
40
+ const [isTranscribing, setIsTranscribing] = useState(false);
41
+ const [transcription, setTranscription] = useState("");
42
+ const { transcribe, gpuInfo, isLoaded: isModelLoaded, isLoading: isModelLoading, error: pipelineError } = usePipeline({
43
+ active,
44
+ debug,
45
+ model
46
+ });
47
+ const { stream, error: audioError, audioLevel } = useAudioStream({
48
+ active,
49
+ debug
50
+ });
51
+ const handleAudioData = useCallback(async (audioData) => {
52
+ if (!isModelLoaded) {
53
+ return;
54
+ }
55
+ if (isTranscribing) {
56
+ return;
57
+ }
58
+ setIsTranscribing(true);
59
+ try {
60
+ const result = await transcribe(audioData, {
61
+ sampling_rate: 16e3,
62
+ chunk_length_s: 5,
63
+ stride_length_s: 1,
64
+ return_timestamps: false,
65
+ language: "english"
66
+ });
67
+ if (result?.text?.trim()) {
68
+ setTranscription((prev) => prev + " " + result.text);
69
+ }
70
+ } catch (err) {
71
+ log.error("transcription error", {
72
+ err
73
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 40, S: void 0 });
74
+ throw err;
75
+ } finally {
76
+ setIsTranscribing(false);
77
+ }
78
+ }, [
79
+ transcribe,
80
+ isTranscribing
81
+ ]);
82
+ log.info("handleAudioData", {
83
+ handleAudioData
84
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 51, S: void 0 });
85
+ useEffect(() => {
86
+ if (debug) {
87
+ log.info("audio state", {
88
+ hasStream: !!stream,
89
+ audioError,
90
+ audioLevel,
91
+ shouldBeActive: active && isModelLoaded
92
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 56, S: void 0 });
93
+ }
94
+ }, [
95
+ debug,
96
+ stream,
97
+ audioError,
98
+ audioLevel,
99
+ active,
100
+ isModelLoaded
101
+ ]);
102
+ useEffect(() => {
103
+ if (debug) {
104
+ log.info("transcription state", {
105
+ active,
106
+ isModelLoaded,
107
+ isModelLoading,
108
+ isTranscribing,
109
+ pipelineError
110
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 73, S: void 0 });
111
+ }
112
+ }, [
113
+ active,
114
+ debug,
115
+ isModelLoaded,
116
+ isModelLoading,
117
+ pipelineError,
118
+ isTranscribing
119
+ ]);
120
+ return /* @__PURE__ */ React2.createElement(DebugInfo, {
121
+ error: audioError || pipelineError || void 0,
122
+ isModelLoading,
123
+ stream,
124
+ isTranscribing,
125
+ transcription,
126
+ audioLevel,
127
+ gpuInfo,
128
+ model,
129
+ debug
130
+ });
131
+ };
132
+ export {
133
+ DebugInfo,
134
+ Voice
135
+ };
136
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/components/Voice/DebugInfo.tsx", "../../../../src/components/Voice/Voice.tsx"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { type FC } from 'react';\n\nexport type DebugInfoProps = {\n error: string;\n isModelLoading: boolean;\n stream: MediaStream | null;\n isTranscribing: boolean;\n transcription: string;\n audioLevel: number;\n gpuInfo: string;\n model: string;\n debug: boolean;\n};\n\nexport const DebugInfo: FC<Partial<DebugInfoProps>> = ({\n error,\n isModelLoading,\n stream,\n isTranscribing,\n transcription,\n audioLevel,\n gpuInfo,\n model,\n debug = false,\n}) => {\n return (\n <div className='p-4'>\n {error && (\n <div className='mb-4 text-red-600'>\n <strong>Error:</strong> {error}\n </div>\n )}\n {isModelLoading && (\n <div className='mb-4'>\n <div>Loading model...</div>\n <div className='text-sm text-gray-500'>This may take a few moments</div>\n </div>\n )}\n {stream ? (\n <div>\n <div className='mb-2 text-green-600'>\n <strong>Status:</strong> Microphone is active\n {debug && audioLevel && (\n <div className='mt-2 w-48 h-5 bg-gray-200 rounded-sm relative'>\n <div\n className='h-full bg-green-500 transition-all duration-100 rounded-sm'\n style={{ width: `${(audioLevel / 255) * 100}%` }}\n />\n </div>\n )}\n </div>\n {isTranscribing && <div className='mb-2 text-gray-500'>Processing audio...</div>}\n {debug && (\n <div className='mb-4 text-sm text-gray-500 space-y-1'>\n <div>Model: {model}</div>\n <div>Sample Rate: 16000 Hz</div>\n <div>Format: audio/wav</div>\n <div>Chunk Size: 10 seconds</div>\n <div>GPU: {gpuInfo || 'Not available'}</div>\n <div>Backend: WebGPU</div>\n </div>\n )}\n {transcription && (\n <div className='mt-4'>\n <strong>Transcription:</strong>\n <p className='mt-2 p-4 bg-gray-100 rounded-sm whitespace-pre-wrap'>{transcription}</p>\n </div>\n )}\n </div>\n ) : (\n <div>{!isModelLoading && !error && <div className='text-gray-500'>Microphone is inactive</div>}</div>\n )}\n </div>\n );\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport React, { useCallback, useEffect, useState } from 'react';\n\nimport { log } from '@dxos/log';\n\nimport { useAudioStream, usePipeline } from '#hooks';\n\nimport { DebugInfo } from './DebugInfo';\n\nexport type VoiceProps = {\n active?: boolean;\n debug?: boolean;\n model?: string;\n};\n\nexport const Voice = ({ active, debug, model = 'Xenova/whisper-base' }: VoiceProps) => {\n const [isTranscribing, setIsTranscribing] = useState(false);\n const [transcription, setTranscription] = useState<string>('');\n\n const {\n transcribe,\n gpuInfo,\n isLoaded: isModelLoaded,\n isLoading: isModelLoading,\n error: pipelineError,\n } = usePipeline({ active, debug, model });\n\n const {\n stream,\n error: audioError,\n audioLevel,\n } = useAudioStream({\n active,\n debug,\n // onAudioData: handleAudioData\n });\n\n const handleAudioData = useCallback(\n async (audioData: Float32Array) => {\n if (!isModelLoaded) {\n return;\n }\n\n if (isTranscribing) {\n return;\n }\n\n setIsTranscribing(true);\n try {\n const result = await transcribe(audioData, {\n sampling_rate: 16000,\n chunk_length_s: 5,\n stride_length_s: 1,\n return_timestamps: false,\n language: 'english',\n });\n\n if (result?.text?.trim()) {\n setTranscription((prev) => prev + ' ' + result.text);\n }\n } catch (err) {\n log.error('transcription error', { err });\n throw err;\n } finally {\n setIsTranscribing(false);\n }\n },\n [transcribe, isTranscribing],\n );\n log.info('handleAudioData', { handleAudioData });\n\n useEffect(() => {\n if (debug) {\n log.info('audio state', {\n hasStream: !!stream,\n audioError,\n audioLevel,\n shouldBeActive: active && isModelLoaded,\n });\n }\n }, [debug, stream, audioError, audioLevel, active, isModelLoaded]);\n\n useEffect(() => {\n if (debug) {\n log.info('transcription state', {\n active,\n isModelLoaded,\n isModelLoading,\n isTranscribing,\n pipelineError,\n });\n }\n }, [active, debug, isModelLoaded, isModelLoading, pipelineError, isTranscribing]);\n\n return (\n <DebugInfo\n error={audioError || pipelineError || undefined}\n isModelLoading={isModelLoading}\n stream={stream}\n isTranscribing={isTranscribing}\n transcription={transcription}\n audioLevel={audioLevel}\n gpuInfo={gpuInfo}\n model={model}\n debug={debug}\n />\n );\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["React", "DebugInfo", "error", "isModelLoading", "stream", "isTranscribing", "transcription", "audioLevel", "gpuInfo", "model", "debug", "div", "className", "strong", "style", "width", "p", "React", "useCallback", "useEffect", "useState", "log", "useAudioStream", "usePipeline", "Voice", "transcription", "setTranscription", "useState", "gpuInfo", "isModelLoaded", "isLoading", "active", "debug", "model", "isTranscribing", "setIsTranscribing", "result", "chunk_length_s", "stride_length_s", "return_timestamps", "language", "text", "log", "err", "transcribe", "info", "useEffect", "hasStream", "audioError", "audioLevel", "shouldBeActive", "isModelLoading", "pipelineError", "stream"]
7
+ }
@@ -0,0 +1,339 @@
1
+ // src/hooks/useAudioStream.ts
2
+ import { useCallback, useEffect, useRef, useState } from "react";
3
+ import { log } from "@dxos/log";
4
+ var __dxlog_file = "/__w/dxos/dxos/packages/plugins/plugin-transformer/src/hooks/useAudioStream.ts";
5
+ var useAudioStream = ({ active, debug, onAudioData }) => {
6
+ const [state, setState] = useState({
7
+ stream: null,
8
+ error: null,
9
+ audioLevel: 0
10
+ });
11
+ const audioContextRef = useRef(null);
12
+ const analyserRef = useRef(null);
13
+ const animationFrameRef = useRef(void 0);
14
+ const workletNodeRef = useRef(null);
15
+ const isProcessingRef = useRef(false);
16
+ const mediaStreamRef = useRef(null);
17
+ const audioBufferRef = useRef([]);
18
+ const updateAudioLevel = useCallback(() => {
19
+ if (analyserRef.current) {
20
+ const dataArray = new Uint8Array(analyserRef.current.frequencyBinCount);
21
+ analyserRef.current.getByteFrequencyData(dataArray);
22
+ const average = dataArray.reduce((acc, val) => acc + val, 0) / dataArray.length;
23
+ setState((prev) => ({
24
+ ...prev,
25
+ audioLevel: average
26
+ }));
27
+ animationFrameRef.current = requestAnimationFrame(updateAudioLevel);
28
+ }
29
+ }, []);
30
+ const cleanup = useCallback(() => {
31
+ log("cleaning up audio resources", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 34, S: void 0 });
32
+ if (mediaStreamRef.current) {
33
+ mediaStreamRef.current.getTracks().forEach((track) => {
34
+ track.stop();
35
+ track.enabled = false;
36
+ });
37
+ mediaStreamRef.current = null;
38
+ }
39
+ if (workletNodeRef.current) {
40
+ workletNodeRef.current.disconnect();
41
+ workletNodeRef.current = null;
42
+ }
43
+ if (analyserRef.current) {
44
+ analyserRef.current.disconnect();
45
+ analyserRef.current = null;
46
+ }
47
+ if (audioContextRef.current) {
48
+ void audioContextRef.current.close();
49
+ audioContextRef.current = null;
50
+ }
51
+ if (animationFrameRef.current) {
52
+ cancelAnimationFrame(animationFrameRef.current);
53
+ animationFrameRef.current = void 0;
54
+ }
55
+ audioBufferRef.current = [];
56
+ setState({
57
+ stream: null,
58
+ error: null,
59
+ audioLevel: 0
60
+ });
61
+ }, [
62
+ debug
63
+ ]);
64
+ useEffect(() => {
65
+ let mounted = true;
66
+ const startStream = async () => {
67
+ try {
68
+ if (active) {
69
+ cleanup();
70
+ log.info("initializing audio stream...", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 75, S: void 0 });
71
+ const stream = await navigator.mediaDevices.getUserMedia({
72
+ audio: {
73
+ channelCount: 1,
74
+ sampleRate: 16e3,
75
+ echoCancellation: true,
76
+ noiseSuppression: true,
77
+ autoGainControl: true
78
+ },
79
+ video: false
80
+ });
81
+ if (!mounted || !active) {
82
+ stream.getTracks().forEach((track) => {
83
+ track.stop();
84
+ track.enabled = false;
85
+ });
86
+ return;
87
+ }
88
+ mediaStreamRef.current = stream;
89
+ const context = new AudioContext({
90
+ sampleRate: 16e3
91
+ });
92
+ await context.audioWorklet.addModule(URL.createObjectURL(new Blob([
93
+ `class AudioProcessor extends AudioWorkletProcessor {
94
+ constructor() {
95
+ super();
96
+ this._buffer = [];
97
+ this._samplesProcessed = 0;
98
+ }
99
+
100
+ process(inputs, outputs) {
101
+ const input = inputs[0];
102
+ const channel = input[0];
103
+
104
+ if (channel) {
105
+ this._buffer.push(new Float32Array(channel));
106
+ this._samplesProcessed += channel.length;
107
+
108
+ // Process every 2 seconds (32000 samples at 16kHz).
109
+ if (this._samplesProcessed >= 32000) {
110
+ const combinedLength = this._buffer.reduce((acc, curr) => acc + curr.length, 0);
111
+ const combinedAudio = new Float32Array(combinedLength);
112
+ let offset = 0;
113
+
114
+ for (const buffer of this._buffer) {
115
+ combinedAudio.set(buffer, offset);
116
+ offset += buffer.length;
117
+ }
118
+
119
+ this.port.postMessage({ type: 'audio-data', data: combinedAudio });
120
+
121
+ // Reset buffer and counter.
122
+ this._buffer = [];
123
+ this._samplesProcessed = 0;
124
+ }
125
+ }
126
+ return true;
127
+ }
128
+ }
129
+
130
+ registerProcessor('audio-processor', AudioProcessor);`
131
+ ], {
132
+ type: "application/javascript"
133
+ })));
134
+ const source = context.createMediaStreamSource(stream);
135
+ const analyser = context.createAnalyser();
136
+ analyserRef.current = analyser;
137
+ const workletNode = new AudioWorkletNode(context, "audio-processor");
138
+ workletNodeRef.current = workletNode;
139
+ workletNode.port.onmessage = async (event) => {
140
+ if (!mounted || !active) {
141
+ return;
142
+ }
143
+ if (event.data.type === "audio-data") {
144
+ isProcessingRef.current = true;
145
+ try {
146
+ log("processing audio", {
147
+ sampleRate: context.sampleRate,
148
+ length: event.data.data.length,
149
+ min: Math.min(...event.data.data),
150
+ max: Math.max(...event.data.data)
151
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 154, S: void 0 });
152
+ await onAudioData?.(event.data.data);
153
+ } catch (err) {
154
+ if (mounted) {
155
+ setState((prev) => ({
156
+ ...prev,
157
+ error: "Error processing audio: " + err.message
158
+ }));
159
+ }
160
+ log.error("audio processing error", {
161
+ err
162
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 168, S: void 0 });
163
+ } finally {
164
+ isProcessingRef.current = false;
165
+ }
166
+ }
167
+ };
168
+ source.connect(analyser);
169
+ analyser.connect(workletNode);
170
+ workletNode.connect(context.destination);
171
+ if (debug) {
172
+ analyser.fftSize = 256;
173
+ updateAudioLevel();
174
+ }
175
+ audioContextRef.current = context;
176
+ if (mounted && active) {
177
+ setState({
178
+ stream,
179
+ error: null,
180
+ audioLevel: 0
181
+ });
182
+ }
183
+ }
184
+ } catch (err) {
185
+ if (mounted) {
186
+ setState((prev) => ({
187
+ ...prev,
188
+ error: "Error accessing microphone: " + err.message,
189
+ stream: null
190
+ }));
191
+ }
192
+ log.error("microphone error", {
193
+ err
194
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 201, S: void 0 });
195
+ cleanup();
196
+ }
197
+ };
198
+ void startStream();
199
+ return () => {
200
+ mounted = false;
201
+ cleanup();
202
+ };
203
+ }, [
204
+ active,
205
+ debug,
206
+ onAudioData,
207
+ updateAudioLevel,
208
+ cleanup
209
+ ]);
210
+ useEffect(() => {
211
+ if (!active) {
212
+ cleanup();
213
+ }
214
+ }, [
215
+ active,
216
+ cleanup
217
+ ]);
218
+ return state;
219
+ };
220
+
221
+ // src/hooks/usePipeline.ts
222
+ import { env, pipeline } from "@xenova/transformers";
223
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState2 } from "react";
224
+ import { invariant } from "@dxos/invariant";
225
+ import { log as log2 } from "@dxos/log";
226
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/plugins/plugin-transformer/src/hooks/usePipeline.ts";
227
+ env.cacheDir = "./.cache";
228
+ env.allowLocalModels = true;
229
+ env.backends.onnx.wasm.numThreads = 1;
230
+ env.backends.onnx.provider = "webgpu";
231
+ env.backends.onnx.webgpu = {
232
+ profilingMode: true
233
+ };
234
+ var usePipeline = ({ active, model, debug }) => {
235
+ const [state, setState] = useState2({
236
+ gpuInfo: "",
237
+ isLoaded: false,
238
+ isLoading: false,
239
+ error: null
240
+ });
241
+ const pipelineRef = useRef2(null);
242
+ useEffect2(() => {
243
+ const loadModel = async () => {
244
+ try {
245
+ setState((prev) => ({
246
+ ...prev,
247
+ isLoading: true,
248
+ error: null
249
+ }));
250
+ if (!navigator.gpu) {
251
+ log2.warn("WebGPU is not supported, falling back to CPU", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 36, S: void 0 });
252
+ setState((prev) => ({
253
+ ...prev,
254
+ gpuInfo: "WebGPU not supported (using CPU)"
255
+ }));
256
+ } else {
257
+ try {
258
+ const adapter = await navigator.gpu.requestAdapter();
259
+ if (!adapter) {
260
+ throw new Error("No GPU adapter found");
261
+ }
262
+ const adapterInfo = adapter.info;
263
+ if (adapterInfo) {
264
+ setState((prev) => ({
265
+ ...prev,
266
+ gpuInfo: `${adapterInfo.description || "GPU"} (${adapterInfo.vendor || "Unknown"})`
267
+ }));
268
+ } else {
269
+ setState((prev) => ({
270
+ ...prev,
271
+ gpuInfo: "GPU Available (details unknown)"
272
+ }));
273
+ }
274
+ } catch (err) {
275
+ log2.warn("WebGPU initialization failed", {
276
+ err
277
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 61, S: void 0 });
278
+ setState((prev) => ({
279
+ ...prev,
280
+ gpuInfo: "GPU initialization failed (using CPU)"
281
+ }));
282
+ }
283
+ }
284
+ const pipe = await pipeline("automatic-speech-recognition", model, {
285
+ quantized: true,
286
+ progress_callback: (progress) => {
287
+ if (debug) {
288
+ log2(`loading model: ${Math.round(progress.progress * 100)}%`, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 74, S: void 0 });
289
+ }
290
+ }
291
+ });
292
+ pipelineRef.current = pipe;
293
+ setState((prev) => ({
294
+ ...prev,
295
+ isLoaded: true,
296
+ isLoading: false
297
+ }));
298
+ log2.info("model loaded successfully", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 84, S: void 0 });
299
+ } catch (err) {
300
+ log2.error("error loading model", {
301
+ err
302
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 86, S: void 0 });
303
+ setState((prev) => ({
304
+ ...prev,
305
+ isLoading: false,
306
+ error: "error loading model: " + err.message
307
+ }));
308
+ }
309
+ };
310
+ if (active) {
311
+ void loadModel();
312
+ }
313
+ return () => {
314
+ pipelineRef.current = null;
315
+ setState((prev) => ({
316
+ ...prev,
317
+ isLoaded: false
318
+ }));
319
+ };
320
+ }, [
321
+ active,
322
+ debug,
323
+ model
324
+ ]);
325
+ const transcribe = async (audioData, options) => {
326
+ invariant(pipelineRef.current, "pipeline not initialized", { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 112, S: void 0, A: ["pipelineRef.current", "'pipeline not initialized'"] });
327
+ const result = await pipelineRef.current(audioData, options);
328
+ return result;
329
+ };
330
+ return {
331
+ ...state,
332
+ transcribe
333
+ };
334
+ };
335
+ export {
336
+ useAudioStream,
337
+ usePipeline
338
+ };
339
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/hooks/useAudioStream.ts", "../../../../src/hooks/usePipeline.ts"],
4
+ "sourcesContent": ["//\n// Copyright 2025 DXOS.org\n//\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { log } from '@dxos/log';\n\nexport type AudioStreamConfig = {\n active?: boolean;\n debug?: boolean;\n onAudioData?: (audioData: Float32Array) => Promise<void>;\n};\n\nexport type AudioStreamState = {\n stream: MediaStream | null;\n error: string | null;\n audioLevel: number;\n};\n\nexport const useAudioStream = ({ active, debug, onAudioData }: AudioStreamConfig) => {\n const [state, setState] = useState<AudioStreamState>({\n stream: null,\n error: null,\n audioLevel: 0,\n });\n\n // TODO(burdon): Convert to class.\n const audioContextRef = useRef<AudioContext | null>(null);\n const analyserRef = useRef<AnalyserNode | null>(null);\n const animationFrameRef = useRef<number>(undefined);\n const workletNodeRef = useRef<AudioWorkletNode | null>(null);\n const isProcessingRef = useRef(false);\n const mediaStreamRef = useRef<MediaStream | null>(null);\n const audioBufferRef = useRef<Float32Array[]>([]);\n\n // Stats for visualization.\n const updateAudioLevel = useCallback(() => {\n if (analyserRef.current) {\n const dataArray = new Uint8Array(analyserRef.current.frequencyBinCount);\n analyserRef.current.getByteFrequencyData(dataArray);\n const average = dataArray.reduce((acc, val) => acc + val, 0) / dataArray.length;\n setState((prev) => ({ ...prev, audioLevel: average }));\n animationFrameRef.current = requestAnimationFrame(updateAudioLevel);\n }\n }, []);\n\n const cleanup = useCallback(() => {\n log('cleaning up audio resources');\n\n // Stop all tracks.\n if (mediaStreamRef.current) {\n mediaStreamRef.current.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n mediaStreamRef.current = null;\n }\n\n // Disconnect and cleanup audio nodes.\n if (workletNodeRef.current) {\n workletNodeRef.current.disconnect();\n workletNodeRef.current = null;\n }\n if (analyserRef.current) {\n analyserRef.current.disconnect();\n analyserRef.current = null;\n }\n if (audioContextRef.current) {\n void audioContextRef.current.close();\n audioContextRef.current = null;\n }\n if (animationFrameRef.current) {\n cancelAnimationFrame(animationFrameRef.current);\n animationFrameRef.current = undefined;\n }\n\n audioBufferRef.current = [];\n setState({\n stream: null,\n error: null,\n audioLevel: 0,\n });\n }, [debug]);\n\n useEffect(() => {\n let mounted = true;\n\n const startStream = async () => {\n try {\n if (active) {\n cleanup();\n log.info('initializing audio stream...');\n const stream = await navigator.mediaDevices.getUserMedia({\n audio: {\n channelCount: 1,\n sampleRate: 16_000,\n echoCancellation: true,\n noiseSuppression: true,\n autoGainControl: true,\n },\n video: false,\n });\n\n if (!mounted || !active) {\n stream.getTracks().forEach((track) => {\n track.stop();\n track.enabled = false;\n });\n return;\n }\n\n mediaStreamRef.current = stream;\n\n // Create AudioContext for proper audio format.\n const context = new AudioContext({ sampleRate: 16_000 });\n\n // Add the audio worklet module.\n await context.audioWorklet.addModule(\n URL.createObjectURL(\n new Blob(\n [\n `class AudioProcessor extends AudioWorkletProcessor {\n constructor() {\n super();\n this._buffer = [];\n this._samplesProcessed = 0;\n }\n\n process(inputs, outputs) {\n const input = inputs[0];\n const channel = input[0];\n \n if (channel) {\n this._buffer.push(new Float32Array(channel));\n this._samplesProcessed += channel.length;\n\n // Process every 2 seconds (32000 samples at 16kHz).\n if (this._samplesProcessed >= 32000) {\n const combinedLength = this._buffer.reduce((acc, curr) => acc + curr.length, 0);\n const combinedAudio = new Float32Array(combinedLength);\n let offset = 0;\n\n for (const buffer of this._buffer) {\n combinedAudio.set(buffer, offset);\n offset += buffer.length;\n }\n\n this.port.postMessage({ type: 'audio-data', data: combinedAudio });\n \n // Reset buffer and counter.\n this._buffer = [];\n this._samplesProcessed = 0;\n }\n }\n return true;\n }\n }\n\n registerProcessor('audio-processor', AudioProcessor);`,\n ],\n { type: 'application/javascript' },\n ),\n ),\n );\n\n const source = context.createMediaStreamSource(stream);\n const analyser = context.createAnalyser();\n analyserRef.current = analyser;\n\n // Create and connect the audio worklet node.\n const workletNode = new AudioWorkletNode(context, 'audio-processor');\n workletNodeRef.current = workletNode;\n\n workletNode.port.onmessage = async (event) => {\n if (!mounted || !active) {\n return;\n }\n\n if (event.data.type === 'audio-data') {\n isProcessingRef.current = true;\n try {\n log('processing audio', {\n sampleRate: context.sampleRate,\n length: event.data.data.length,\n min: Math.min(...event.data.data),\n max: Math.max(...event.data.data),\n });\n\n await onAudioData?.(event.data.data);\n } catch (err) {\n if (mounted) {\n setState((prev) => ({\n ...prev,\n error: 'Error processing audio: ' + (err as Error).message,\n }));\n }\n log.error('audio processing error', { err });\n } finally {\n isProcessingRef.current = false;\n }\n }\n };\n\n // Connect the audio nodes.\n source.connect(analyser);\n analyser.connect(workletNode);\n workletNode.connect(context.destination);\n\n if (debug) {\n analyser.fftSize = 256;\n updateAudioLevel();\n }\n\n audioContextRef.current = context;\n if (mounted && active) {\n setState({\n stream,\n error: null,\n audioLevel: 0,\n });\n }\n }\n } catch (err) {\n if (mounted) {\n setState((prev) => ({\n ...prev,\n error: 'Error accessing microphone: ' + (err as Error).message,\n stream: null,\n }));\n }\n log.error('microphone error', { err });\n cleanup();\n }\n };\n\n void startStream();\n\n return () => {\n mounted = false;\n cleanup();\n };\n }, [active, debug, onAudioData, updateAudioLevel, cleanup]);\n\n useEffect(() => {\n if (!active) {\n cleanup();\n }\n }, [active, cleanup]);\n\n return state;\n};\n", "//\n// Copyright 2025 DXOS.org\n//\n\nimport { type Pipeline, env, pipeline } from '@xenova/transformers';\nimport { useEffect, useRef, useState } from 'react';\n\nimport { invariant } from '@dxos/invariant';\nimport { log } from '@dxos/log';\n\n// Configure cache and runtime settings.\nenv.cacheDir = './.cache';\nenv.allowLocalModels = true;\n\n// Configure ONNX runtime for WebGPU.\n(env.backends.onnx as any).wasm.numThreads = 1;\n(env.backends.onnx as any).provider = 'webgpu';\n(env.backends.onnx as any).webgpu = {\n profilingMode: true,\n};\n\nexport type PipelineConfig = {\n active?: boolean;\n debug?: boolean;\n model: string;\n};\n\nexport type PipelineState = {\n gpuInfo: string;\n isLoaded: boolean;\n isLoading: boolean;\n error: string | null;\n};\n\n// TODO(burdon): Document external API.\nexport type TranscriptionOptions = {\n sampling_rate: number;\n chunk_length_s: number;\n stride_length_s: number;\n return_timestamps: boolean;\n language: string;\n};\n\nexport const usePipeline = ({ active, model, debug }: PipelineConfig) => {\n const [state, setState] = useState<PipelineState>({\n gpuInfo: '',\n isLoaded: false,\n isLoading: false,\n error: null,\n });\n\n const pipelineRef = useRef<Pipeline | null>(null);\n\n // TODO(burdon): Factor out loading model. Separate tests.\n useEffect(() => {\n const loadModel = async () => {\n try {\n setState((prev) => ({ ...prev, isLoading: true, error: null }));\n\n // Check WebGPU support.\n if (!navigator.gpu) {\n log.warn('WebGPU is not supported, falling back to CPU');\n setState((prev) => ({ ...prev, gpuInfo: 'WebGPU not supported (using CPU)' }));\n } else {\n try {\n const adapter = await navigator.gpu.requestAdapter();\n if (!adapter) {\n throw new Error('No GPU adapter found');\n }\n\n // Get adapter info from the info property (modern WebGPU API).\n const adapterInfo = adapter.info;\n if (adapterInfo) {\n setState((prev) => ({\n ...prev,\n gpuInfo: `${adapterInfo.description || 'GPU'} (${adapterInfo.vendor || 'Unknown'})`,\n }));\n } else {\n setState((prev) => ({ ...prev, gpuInfo: 'GPU Available (details unknown)' }));\n }\n } catch (err) {\n log.warn('WebGPU initialization failed', { err });\n setState((prev) => ({ ...prev, gpuInfo: 'GPU initialization failed (using CPU)' }));\n }\n }\n\n const pipe = await pipeline('automatic-speech-recognition', model, {\n quantized: true,\n progress_callback: (progress: any) => {\n if (debug) {\n log(`loading model: ${Math.round(progress.progress * 100)}%`);\n }\n },\n });\n\n pipelineRef.current = pipe;\n setState((prev) => ({ ...prev, isLoaded: true, isLoading: false }));\n log.info('model loaded successfully');\n } catch (err) {\n log.error('error loading model', { err });\n setState((prev) => ({\n ...prev,\n isLoading: false,\n error: 'error loading model: ' + (err as Error).message,\n }));\n }\n };\n\n if (active) {\n void loadModel();\n }\n\n return () => {\n pipelineRef.current = null;\n setState((prev) => ({ ...prev, isLoaded: false }));\n };\n }, [active, debug, model]);\n\n const transcribe = async (audioData: Float32Array, options: TranscriptionOptions) => {\n invariant(pipelineRef.current, 'pipeline not initialized');\n const result = await pipelineRef.current(audioData, options);\n return result;\n };\n\n return {\n ...state,\n transcribe,\n };\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["useCallback", "useEffect", "useRef", "useState", "log", "useAudioStream", "stream", "error", "audioLevel", "animationFrameRef", "undefined", "workletNodeRef", "isProcessingRef", "mediaStreamRef", "audioBufferRef", "updateAudioLevel", "dataArray", "Uint8Array", "analyserRef", "current", "getByteFrequencyData", "average", "acc", "val", "setState", "prev", "enabled", "audioContextRef", "debug", "startStream", "audio", "channelCount", "sampleRate", "echoCancellation", "noiseSuppression", "autoGainControl", "video", "mounted", "stop", "track", "context", "AudioContext", "source", "analyser", "workletNode", "onmessage", "event", "active", "length", "data", "min", "max", "Math", "onAudioData", "connect", "cleanup", "env", "pipeline", "useEffect", "useRef", "useState", "invariant", "log", "__dxlog_file", "backends", "numThreads", "onnx", "webgpu", "profilingMode", "usePipeline", "gpuInfo", "isLoaded", "isLoading", "error", "pipelineRef", "prev", "navigator", "setState", "Error", "err", "progress_callback", "progress", "debug", "Math", "active", "model", "current", "audioData", "result", "transcribe"]
7
+ }
@@ -0,0 +1,7 @@
1
+ import {
2
+ meta
3
+ } from "./chunk-BKDV4JXC.mjs";
4
+ export {
5
+ meta
6
+ };
7
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"inputs":{"src/meta.ts":{"bytes":1774,"imports":[{"path":"@dxos/util","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":368,"imports":[{"path":"src/meta.ts","kind":"import-statement","original":"./meta"}],"format":"esm"},"src/TransformerPlugin.tsx":{"bytes":2327,"imports":[{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/app-toolkit","kind":"import-statement","external":true},{"path":"#meta","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true}],"format":"esm"},"src/components/Voice/DebugInfo.tsx":{"bytes":7253,"imports":[{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/components/Voice/Voice.tsx":{"bytes":9591,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"#hooks","kind":"import-statement","external":true},{"path":"src/components/Voice/DebugInfo.tsx","kind":"import-statement","original":"./DebugInfo"}],"format":"esm"},"src/components/Voice/index.ts":{"bytes":458,"imports":[{"path":"src/components/Voice/DebugInfo.tsx","kind":"import-statement","original":"./DebugInfo"},{"path":"src/components/Voice/Voice.tsx","kind":"import-statement","original":"./Voice"}],"format":"esm"},"src/components/index.ts":{"bytes":369,"imports":[{"path":"src/components/Voice/index.ts","kind":"import-statement","original":"./Voice"}],"format":"esm"},"src/hooks/useAudioStream.ts":{"bytes":26320,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"format":"esm"},"src/hooks/usePipeline.ts":{"bytes":13877,"imports":[{"path":"@xenova/transformers","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"format":"esm"},"src/hooks/index.ts":{"bytes":489,"imports":[{"path":"src/hooks/useAudioStream.ts","kind":"import-statement","original":"./useAudioStream"},{"path":"src/hooks/usePipeline.ts","kind":"import-statement","original":"./usePipeline"}],"format":"esm"},"src/plugin.ts":{"bytes":876,"imports":[{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"src/meta.ts","kind":"import-statement","original":"./meta"},{"path":"#plugin","kind":"dynamic-import","external":true}],"format":"esm"},"src/translations.ts":{"bytes":1041,"imports":[{"path":"#meta","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/lib/neutral/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":93},"dist/lib/neutral/index.mjs":{"imports":[{"path":"dist/lib/neutral/chunk-BKDV4JXC.mjs","kind":"import-statement"}],"exports":["meta"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0}},"bytes":101},"dist/lib/neutral/TransformerPlugin.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":1149},"dist/lib/neutral/TransformerPlugin.mjs":{"imports":[{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"@dxos/app-toolkit","kind":"import-statement","external":true},{"path":"#meta","kind":"import-statement","external":true},{"path":"#translations","kind":"import-statement","external":true}],"exports":["TransformerPlugin","default"],"entryPoint":"src/TransformerPlugin.tsx","inputs":{"src/TransformerPlugin.tsx":{"bytesInOutput":541}},"bytes":689},"dist/lib/neutral/components/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":8435},"dist/lib/neutral/components/index.mjs":{"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"#hooks","kind":"import-statement","external":true}],"exports":["DebugInfo","Voice"],"entryPoint":"src/components/index.ts","inputs":{"src/components/Voice/DebugInfo.tsx":{"bytesInOutput":2426},"src/components/Voice/index.ts":{"bytesInOutput":0},"src/components/Voice/Voice.tsx":{"bytesInOutput":2573},"src/components/index.ts":{"bytesInOutput":0}},"bytes":5140},"dist/lib/neutral/hooks/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":18099},"dist/lib/neutral/hooks/index.mjs":{"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true},{"path":"@xenova/transformers","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/invariant","kind":"import-statement","external":true},{"path":"@dxos/log","kind":"import-statement","external":true}],"exports":["useAudioStream","usePipeline"],"entryPoint":"src/hooks/index.ts","inputs":{"src/hooks/useAudioStream.ts":{"bytesInOutput":7364},"src/hooks/index.ts":{"bytesInOutput":0},"src/hooks/usePipeline.ts":{"bytesInOutput":3729}},"bytes":11232},"dist/lib/neutral/meta.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":93},"dist/lib/neutral/meta.mjs":{"imports":[{"path":"dist/lib/neutral/chunk-BKDV4JXC.mjs","kind":"import-statement"}],"exports":["meta"],"entryPoint":"src/meta.ts","inputs":{},"bytes":100},"dist/lib/neutral/plugin.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":451},"dist/lib/neutral/plugin.mjs":{"imports":[{"path":"dist/lib/neutral/chunk-BKDV4JXC.mjs","kind":"import-statement"},{"path":"@dxos/app-framework","kind":"import-statement","external":true},{"path":"#plugin","kind":"dynamic-import","external":true}],"exports":["TransformerPlugin"],"entryPoint":"src/plugin.ts","inputs":{"src/plugin.ts":{"bytesInOutput":114}},"bytes":247},"dist/lib/neutral/chunk-BKDV4JXC.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":872},"dist/lib/neutral/chunk-BKDV4JXC.mjs":{"imports":[{"path":"@dxos/util","kind":"import-statement","external":true}],"exports":["meta"],"inputs":{"src/meta.ts":{"bytesInOutput":451}},"bytes":530},"dist/lib/neutral/translations.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":548},"dist/lib/neutral/translations.mjs":{"imports":[{"path":"#meta","kind":"import-statement","external":true}],"exports":["translations"],"entryPoint":"src/translations.ts","inputs":{"src/translations.ts":{"bytesInOutput":148}},"bytes":240}}}
@@ -0,0 +1,7 @@
1
+ import {
2
+ meta
3
+ } from "./chunk-BKDV4JXC.mjs";
4
+ export {
5
+ meta
6
+ };
7
+ //# sourceMappingURL=meta.mjs.map