@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.
- package/dist/lib/neutral/TransformerPlugin.mjs +25 -0
- package/dist/lib/neutral/TransformerPlugin.mjs.map +7 -0
- package/dist/lib/neutral/chunk-BKDV4JXC.mjs +20 -0
- package/dist/lib/neutral/chunk-BKDV4JXC.mjs.map +7 -0
- package/dist/lib/neutral/components/index.mjs +136 -0
- package/dist/lib/neutral/components/index.mjs.map +7 -0
- package/dist/lib/neutral/hooks/index.mjs +339 -0
- package/dist/lib/neutral/hooks/index.mjs.map +7 -0
- package/dist/lib/neutral/index.mjs +7 -0
- package/dist/lib/neutral/meta.json +1 -0
- package/dist/lib/neutral/meta.mjs +7 -0
- package/dist/lib/neutral/plugin.mjs +11 -0
- package/dist/lib/neutral/plugin.mjs.map +7 -0
- package/dist/lib/neutral/translations.mjs +15 -0
- package/dist/lib/neutral/translations.mjs.map +7 -0
- package/dist/types/src/TransformerPlugin.d.ts +3 -1
- package/dist/types/src/TransformerPlugin.d.ts.map +1 -1
- package/dist/types/src/TransformerPlugin.test.d.ts +2 -0
- package/dist/types/src/TransformerPlugin.test.d.ts.map +1 -0
- package/dist/types/src/components/Voice/DebugInfo.d.ts.map +1 -0
- package/dist/types/src/components/Voice/Voice.d.ts.map +1 -0
- package/dist/types/src/components/{Voice.stories.d.ts → Voice/Voice.stories.d.ts} +0 -1
- package/dist/types/src/components/Voice/Voice.stories.d.ts.map +1 -0
- package/dist/types/src/components/Voice/index.d.ts +3 -0
- package/dist/types/src/components/Voice/index.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +2 -0
- package/dist/types/src/components/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useAudioStream.d.ts.map +1 -1
- package/dist/types/src/hooks/usePipeline.d.ts +1 -16
- package/dist/types/src/hooks/usePipeline.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +0 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/meta.d.ts +2 -3
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/plugin.d.ts +3 -0
- package/dist/types/src/plugin.d.ts.map +1 -0
- package/dist/types/src/testing/node-pipeline.d.ts +1 -1
- package/dist/types/src/testing/node-pipeline.d.ts.map +1 -1
- package/dist/types/src/testing/pipeline.d.ts.map +1 -1
- package/dist/types/src/testing/web-pipeline.d.ts +1 -1
- package/dist/types/src/testing/web-pipeline.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +2 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +76 -50
- package/src/TransformerPlugin.test.ts +25 -0
- package/src/TransformerPlugin.tsx +16 -27
- package/src/components/{DebugInfo.tsx → Voice/DebugInfo.tsx} +3 -3
- package/src/components/{Voice.stories.tsx → Voice/Voice.stories.tsx} +3 -5
- package/src/components/{Voice.tsx → Voice/Voice.tsx} +1 -1
- package/src/components/Voice/index.ts +6 -0
- package/src/{capabilities → components}/index.ts +2 -0
- package/src/hooks/useAudioStream.ts +1 -1
- package/src/hooks/usePipeline.ts +9 -33
- package/src/index.ts +0 -2
- package/src/meta.ts +8 -6
- package/src/plugin.ts +9 -0
- package/src/translations.ts +2 -2
- package/dist/lib/browser/index.mjs +0 -52
- package/dist/lib/browser/index.mjs.map +0 -7
- package/dist/lib/browser/meta.json +0 -1
- package/dist/lib/browser/types/index.mjs +0 -1
- package/dist/lib/node-esm/index.mjs +0 -54
- package/dist/lib/node-esm/index.mjs.map +0 -7
- package/dist/lib/node-esm/meta.json +0 -1
- package/dist/lib/node-esm/types/index.mjs +0 -2
- package/dist/types/src/capabilities/index.d.ts +0 -1
- package/dist/types/src/capabilities/index.d.ts.map +0 -1
- package/dist/types/src/components/DebugInfo.d.ts.map +0 -1
- package/dist/types/src/components/Voice.d.ts.map +0 -1
- package/dist/types/src/components/Voice.stories.d.ts.map +0 -1
- /package/dist/lib/{browser/types → neutral}/index.mjs.map +0 -0
- /package/dist/lib/{node-esm/types/index.mjs.map → neutral/meta.mjs.map} +0 -0
- /package/dist/types/src/components/{DebugInfo.d.ts → Voice/DebugInfo.d.ts} +0 -0
- /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": ";AAIA,SAASA,aAAaC,WAAWC,QAAQC,gBAAgB;AAEzD,SAASC,WAAW;AAcpB,IAAA,eAAaC;IAETC,iBAAQ,CAAA,EAAA,QAAA,OAAA,YAAA,MAAA;QACRC,CAAAA,OAAO,QAAA,IAAA,SAAA;IACPC,QAAAA;IACF,OAAA;IAEA,YAAA;EACA,CAAA;AAEA,QAAMC,kBAAAA,OAAoBP,IAAeQ;AACzC,QAAMC,cAAAA,OAAiBT,IAAgC;AACvD,QAAMU,oBAAkBV,OAAO,MAAA;AAC/B,QAAMW,iBAAiBX,OAA2B,IAAA;AAClD,QAAMY,kBAAiBZ,OAAuB,KAAE;AAEhD,QAAA,iBAAA,OAA2B,IAAA;AAC3B,QAAMa,iBAAAA,OAAmBf,CAAAA,CAAAA;2BAEfgB,YAAgBC,MAAWC;QACjCA,YAAYC,SAAQC;AACpB,YAAMC,YAAUL,IAAAA,WAAiB,YAAcM,QAAMC,iBAAUP;AAC/DQ,kBAAUC,QAAU,qBAAA,SAAA;sBAAS,UAAA,OAAA,CAAA,KAAA,QAAA,MAAA,KAAA,CAAA,IAAA,UAAA;eAAEjB,CAAAA,UAAAA;QAAoB,GAAA;QACnDC,YAAkBU;MACpB,EAAA;AACG,wBAAA,UAAA,sBAAA,gBAAA;IAEL;MACEf,CAAAA;QAEA,UAAA,YAAmB,MAAA;AACnB,QAAIS,+BAAwB,QAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,OAAA,CAAA;uBAEd,SAAA;qBACJa,QAAU,UAAA,EAAA,QAAA,CAAA,UAAA;AAClB,cAAA,KAAA;AACAb,cAAAA,UAAeM;MACjB,CAAA;AAEA,qBAAA,UAAA;IACA;QAEER,eAAeQ,SAAO;AACxB,qBAAA,QAAA,WAAA;AACID,qBAAYC,UAAS;;QAEvBD,YAAYC,SAAO;AACrB,kBAAA,QAAA,WAAA;AACIQ,kBAAAA,UAAgBR;;QAElBQ,gBAAgBR,SAAO;AACzB,WAAA,gBAAA,QAAA,MAAA;AACIV,sBAAAA,UAAyB;;QAE3BA,kBAAkBU,SAAO;AAC3B,2BAAA,kBAAA,OAAA;AAEAL,wBAAsB,UAAK;IAC3BU;mBACU,UAAA,CAAA;aACRjB;MACAC,QAAAA;MACF,OAAA;MACC,YAAA;IAACoB,CAAAA;KAAM;IAEV3B;;YAGQ4B,MAAAA;QACJ,UAAI;wBACU,YAAA;;YAEVzB,QAAQ;AACR,kBAAME;cACJwB,KAAAA,gCAAO,QAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,IAAA,GAAA,OAAA,CAAA;yBACLC,MAAAA,UAAc,aAAA,aAAA;mBACdC;cACAC,cAAAA;cACAC,YAAAA;cACAC,kBAAiB;cACnB,kBAAA;cACAC,iBAAO;YACT;YAEI,OAACC;;0BAEKC,CAAAA,QAAI;mBACVC,UAAa,EAAA,QAAG,CAAA,UAAA;AAClB,oBAAA,KAAA;AACA,oBAAA,UAAA;YACF,CAAA;AAEA1B;UAEA;AACA,yBAAM2B,UAAcC;AAAkC,gBAAA,UAAA,IAAA,aAAA;YAEtD,YAAA;UACA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UA2CuC,GAAA;YAKvC,MAAMC;UACN,CAAA,CAAA,CAAA;AACAxB,gBAAAA,SAAYC,QAAUwB,wBAAAA,MAAAA;AAEtB,gBAAA,WAAA,QAAA,eAAA;AACA,sBAAMC,UAAc;AAGpBA,gBAAAA,cAAiBC,IAAAA,iBAAmBC,SAAAA,iBAAAA;yBAC7BT,UAAYU;sBACf,KAAA,YAAA,OAAA,UAAA;AACF,gBAAA,CAAA,WAAA,CAAA,QAAA;AAEID;;gBAEF,MAAI,KAAA,SAAA,cAAA;8BACE,UAAA;;oBAEFE,oBAAmBC;kBACnBC,YAAUA,QAAOJ;kBACjBK,QAAKC,MAAQ,KAAIN,KAAMG;kBACzB,KAAA,KAAA,IAAA,GAAA,MAAA,KAAA,IAAA;kBAEA,KAAMI,KAAAA,IAAAA,GAAcP,MAAMG,KAAKA,IAAI;gBACnC,GAAA,EAAA,YAAY,YAAA,GAAA,cAAA,GAAA,KAAA,GAAA,OAAA,CAAA;AACZ,sBAAIZ,cAAS,MAAA,KAAA,IAAA;uBACXb,KAAAA;6BACE;2BACAjB,CAAAA,UAAO;oBACT,GAAA;oBACF,OAAA,6BAAA,IAAA;kBACIA,EAAM;;AAAgC,oBAAA,MAAA,0BAAA;kBAC5C;gBACEK,GAAAA,EAAAA,YAAAA,YAAuB,GAAG,cAAA,GAAA,KAAA,GAAA,OAAA,CAAA;cAC5B,UAAA;AACF,gCAAA,UAAA;cACF;YAEA;UACA8B;AAEAE,iBAAAA,QAAYU,QAAQd;AAEpB,mBAAIZ,QAAO,WAAA;sBACTe,QAAgB,QAAG,WAAA;cACnB5B,OAAAA;AACF,qBAAA,UAAA;AAEAY,6BAAgBR;UAChB;0BACW,UAAA;yBACPb,QAAAA;qBACAC;cACAC;cACF,OAAA;cACF,YAAA;YACF,CAAA;UACA;QACA;eACEgB,KAAAA;qBACE;mBACAjB,CAAAA,UAAO;YACPD,GAAAA;YACF,OAAA,iCAAA,IAAA;YACF,QAAA;UACIC,EAAM;;AAA0B,YAAA,MAAA,oBAAA;UACpCgD;QACF,GAAA,EAAA,YAAA,YAAA,GAAA,cAAA,GAAA,KAAA,GAAA,OAAA,CAAA;AACF,gBAAA;MAEA;IAEA;SACElB,YAAU;WACVkB,MAAAA;AACF,gBAAA;AACC,cAAA;IAACR;;IAAeM;IAAatC;IAAkBwC;IAAQ;IAE1DtD;;YAEIsD,MAAAA;AACF,QAAA,CAAA,QAAA;AACC,cAAA;IAACR;;IAAgB;IAEpB;EACA,CAAA;;;;;ACvPF,SAAwBS,KAAKC,gBAAgB;AAC7C,SAASC,aAAAA,YAAWC,UAAAA,SAAQC,YAAAA,iBAAgB;AAE5C,SAASC,iBAAiB;AAC1B,SAASC,OAAAA,YAAW;AAEpB,IAAAC,gBAAA;AAIA,IAAA,WAAA;AACCP,IAAIQ,mBAA2BC;AAE/BT,IAAIQ,SAASE,KAAaC,KAAAA,aAAS;IAClCC,SAAAA,KAAAA,WAAe;AACjB,IAAA,SAAA,KAAA,SAAA;EAwBA,eAAaC;;IAETC,cAAS,CAAA,EAAA,QAAA,OAAA,MAAA,MAAA;QACTC,CAAAA,OAAU,QAAA,IAAAX,UAAA;IACVY,SAAAA;IACAC,UAAO;IACT,WAAA;IAEA,OAAMC;EAEN,CAAA;AACAhB,QAAAA,cAAUC,QAAA,IAAA;aAEN,MAAI;sBACQgB,YAAU;;iBAAWH,CAAAA,UAAAA;UAAiBC,GAAAA;UAAY,WAAA;UAE5D,OAAA;QACI,EAACG;YAEHC,CAAAA,UAAUF,KAAAA;oBAAY,gDAAO,QAAA,EAAA,YAAA,YAAA,GAAAZ,eAAA,GAAA,IAAA,GAAA,OAAA,CAAA;mBAAEO,CAAAA,UAAS;YAAmC,GAAA;YACtE,SAAA;UACD,EAAA;;cAEF;kBACE,UAAUQ,MAAM,UAAA,IAAA,eAAA;AAClB,gBAAA,CAAA,SAAA;AAEA,oBAAA,IAAA,MAAA,sBAAA;YACA;kBAEED,cAAUF,QAAU;6BACfA;uBACHL,CAAAA,UAAS;gBACX,GAAA;gBACK,SAAA,GAAA,YAAA,eAAA,KAAA,KAAA,YAAA,UAAA,SAAA;cACLO,EAAAA;;uBAA+BP,CAAAA,UAAS;gBAAkC,GAAA;gBAC5E,SAAA;cACOS,EAAK;YACZjB;mBAA2CiB,KAAAA;AAAI,YAAAjB,KAAA,KAAA,gCAAA;cAC/Ce;6BAAyBF,YAAI,GAAAZ,eAAA,GAAA,IAAA,GAAA,OAAA,CAAA;qBAAEO,CAAAA,UAAS;cAAwC,GAAA;cAClF,SAAA;YACF,EAAA;UAEA;;cAEEU,OAAAA,MAAAA,SAAoBC,gCAAAA,OAAAA;qBACdC;6BACG,CAAA,aAAiBC;AACxB,gBAAA,OAAA;AACF,cAAArB,KAAA,kBAAA,KAAA,MAAA,SAAA,WAAA,GAAA,CAAA,KAAA,QAAA,EAAA,YAAA,YAAA,GAAAC,eAAA,GAAA,IAAA,GAAA,OAAA,CAAA;YACF;UAEAW;QACAG,CAAAA;oBAAyBF,UAAI;iBAAEJ,CAAAA,UAAU;UAAMC,GAAAA;UAAiB,UAAA;UACxD,WAAC;QACT,EAAOO;AACPjB,QAAAA,KAAIW,KAAK,6BAAwB,QAAA,EAAA,YAAA,YAAA,GAAAV,eAAA,GAAA,IAAA,GAAA,OAAA,CAAA;eAAEgB,KAAAA;AAAI,QAAAjB,KAAA,MAAA,uBAAA;UACvCe;yBACKF,YAAI,GAAAZ,eAAA,GAAA,IAAA,GAAA,OAAA,CAAA;iBACPS,CAAAA,UAAAA;UACAC,GAAAA;UACF,WAAA;UACF,OAAA,0BAAA,IAAA;QACF,EAAA;MAEIW;;AAEJ,QAAA,QAAA;AAEA,WAAO,UAAA;;WAELP,MAAAA;kBAAyBF,UAAI;eAAEJ,CAAAA,UAAU;QAAM,GAAA;QACjD,UAAA;MACC,EAAA;IAACa;;IAAeC;IAAM;IAEzB;;QAEE,aAAe,OAAMX,WAAYY,YAAQC;AACzC,cAAOC,YAAAA,SAAAA,4BAAAA,EAAAA,YAAAA,YAAAA,GAAAA,eAAAA,GAAAA,KAAAA,GAAAA,QAAAA,GAAAA,CAAAA,uBAAAA,4BAAAA,EAAAA,CAAAA;AACT,UAAA,SAAA,MAAA,YAAA,QAAA,WAAA,OAAA;AAEA,WAAO;;SAELC;IACF,GAAA;IACA;;;",
|
|
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 @@
|
|
|
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}}}
|