feat: add Silero VAD toggle to audio pipeline
Integrates @ricky0123/vad-web's MicVAD as an optional voice activity detector alongside the noise gate. When enabled, the Silero ONNX model classifies each audio frame as speech or silence; silence frames mute the worklet's output via a new VAD gate message. VAD is wired into Publisher.ts alongside the existing noise gate transformer. Vite is configured to copy the worklet bundle, ONNX model, and ORT WASM files to /vad/ so they're reachable at runtime. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -132,6 +132,7 @@
|
||||
"vite-plugin-generate-file": "^0.3.0",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-node-stdlib-browser": "^0.2.1",
|
||||
"vite-plugin-static-copy": "^4.0.0",
|
||||
"vite-plugin-svgr": "^4.0.0",
|
||||
"vitest": "^4.0.18",
|
||||
"vitest-axe": "^1.0.0-pre.3"
|
||||
@@ -145,5 +146,8 @@
|
||||
"qs": "^6.14.1",
|
||||
"js-yaml": "^4.1.1"
|
||||
},
|
||||
"packageManager": "yarn@4.7.0"
|
||||
"packageManager": "yarn@4.7.0",
|
||||
"dependencies": {
|
||||
"@ricky0123/vad-web": "^0.0.30"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ interface NoiseGateParams {
|
||||
transientReleaseMs: number; // how quickly suppression fades after transient ends
|
||||
}
|
||||
|
||||
interface VADGateMessage {
|
||||
type: "vad-gate";
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
function dbToLinear(db: number): number {
|
||||
return Math.pow(10, db / 20);
|
||||
}
|
||||
@@ -65,12 +70,19 @@ class NoiseGateProcessor extends AudioWorkletProcessor {
|
||||
// Exponential smoothing coefficient for background RMS (~200ms time constant)
|
||||
private rmsCoeff = Math.exp(-1.0 / (0.2 * sampleRate));
|
||||
|
||||
// VAD gate state (controlled externally via port message)
|
||||
private vadGateOpen = true; // starts open until VAD sends its first decision
|
||||
|
||||
private logCounter = 0;
|
||||
|
||||
public constructor() {
|
||||
super();
|
||||
this.port.onmessage = (e: MessageEvent<NoiseGateParams>): void => {
|
||||
this.updateParams(e.data);
|
||||
this.port.onmessage = (e: MessageEvent<NoiseGateParams | VADGateMessage>): void => {
|
||||
if ((e.data as VADGateMessage).type === "vad-gate") {
|
||||
this.vadGateOpen = (e.data as VADGateMessage).open;
|
||||
} else {
|
||||
this.updateParams(e.data as NoiseGateParams);
|
||||
}
|
||||
};
|
||||
this.updateParams({
|
||||
threshold: -60, attackMs: 25, holdMs: 200, releaseMs: 150,
|
||||
@@ -148,7 +160,7 @@ class NoiseGateProcessor extends AudioWorkletProcessor {
|
||||
}
|
||||
}
|
||||
|
||||
const gain = this.gateAttenuation * transientGain;
|
||||
const gain = this.gateAttenuation * transientGain * (this.vadGateOpen ? 1.0 : 0.0);
|
||||
|
||||
for (let c = 0; c < output.length; c++) {
|
||||
const inCh = input[c] ?? input[0];
|
||||
|
||||
@@ -119,6 +119,11 @@ export class NoiseGateTransformer implements AudioTrackProcessor {
|
||||
this.sendParams();
|
||||
}
|
||||
|
||||
/** Tell the worklet to open or close the VAD-controlled gate. */
|
||||
public setVADOpen(open: boolean): void {
|
||||
this.workletNode?.port.postMessage({ type: "vad-gate", open });
|
||||
}
|
||||
|
||||
private sendParams(): void {
|
||||
if (!this.workletNode) return;
|
||||
log.debug("sendParams:", this.params);
|
||||
|
||||
85
src/livekit/SileroVADGate.ts
Normal file
85
src/livekit/SileroVADGate.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
Copyright 2026 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { MicVAD, getDefaultRealTimeVADOptions } from "@ricky0123/vad-web";
|
||||
import { logger } from "matrix-js-sdk/lib/logger";
|
||||
|
||||
const log = logger.getChild("[SileroVADGate]");
|
||||
|
||||
const VAD_BASE_PATH = "/vad/";
|
||||
|
||||
/**
|
||||
* Wraps @ricky0123/vad-web's MicVAD to feed speech/silence decisions into the
|
||||
* NoiseGateTransformer's VAD gate. Instead of creating its own microphone
|
||||
* stream, it receives the existing LiveKit MediaStream so the VAD sees exactly
|
||||
* the same audio the worklet processes.
|
||||
*
|
||||
* Usage:
|
||||
* const gate = new SileroVADGate(stream, audioContext);
|
||||
* gate.onSpeechStart = () => transformer.setVADOpen(true);
|
||||
* gate.onSpeechEnd = () => transformer.setVADOpen(false);
|
||||
* await gate.start();
|
||||
* // later:
|
||||
* await gate.destroy();
|
||||
*/
|
||||
export class SileroVADGate {
|
||||
public onSpeechStart: () => void = () => {};
|
||||
public onSpeechEnd: () => void = () => {};
|
||||
|
||||
private vad: MicVAD | null = null;
|
||||
private readonly stream: MediaStream;
|
||||
private readonly audioContext: AudioContext;
|
||||
|
||||
public constructor(stream: MediaStream, audioContext: AudioContext) {
|
||||
this.stream = stream;
|
||||
this.audioContext = audioContext;
|
||||
}
|
||||
|
||||
public async start(): Promise<void> {
|
||||
const stream = this.stream;
|
||||
const audioContext = this.audioContext;
|
||||
|
||||
log.info("initialising MicVAD, baseAssetPath:", VAD_BASE_PATH);
|
||||
|
||||
this.vad = await MicVAD.new({
|
||||
...getDefaultRealTimeVADOptions("legacy"),
|
||||
audioContext,
|
||||
baseAssetPath: VAD_BASE_PATH,
|
||||
onnxWASMBasePath: VAD_BASE_PATH,
|
||||
startOnLoad: false,
|
||||
// Provide the existing stream instead of calling getUserMedia
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
getStream: async (): Promise<MediaStream> => stream,
|
||||
pauseStream: async (): Promise<void> => {},
|
||||
// eslint-disable-next-line @typescript-eslint/require-await
|
||||
resumeStream: async (): Promise<MediaStream> => stream,
|
||||
onSpeechStart: (): void => {
|
||||
log.debug("speech start");
|
||||
this.onSpeechStart();
|
||||
},
|
||||
onSpeechEnd: (): void => {
|
||||
log.debug("speech end");
|
||||
this.onSpeechEnd();
|
||||
},
|
||||
onVADMisfire: (): void => {
|
||||
log.debug("VAD misfire");
|
||||
},
|
||||
onFrameProcessed: (): void => {},
|
||||
onSpeechRealStart: (): void => {},
|
||||
});
|
||||
|
||||
await this.vad.start();
|
||||
log.info("MicVAD started");
|
||||
}
|
||||
|
||||
public async destroy(): Promise<void> {
|
||||
if (this.vad) {
|
||||
await this.vad.destroy();
|
||||
this.vad = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
transientSuppressorEnabled as transientSuppressorEnabledSetting,
|
||||
transientThreshold as transientThresholdSetting,
|
||||
transientRelease as transientReleaseSetting,
|
||||
vadEnabled as vadEnabledSetting,
|
||||
} from "./settings";
|
||||
import { PreferencesSettingsTab } from "./PreferencesSettingsTab";
|
||||
import { Slider } from "../Slider";
|
||||
@@ -129,6 +130,9 @@ export const SettingsModal: FC<Props> = ({
|
||||
|
||||
const [showAdvancedGate, setShowAdvancedGate] = useState(false);
|
||||
|
||||
// Voice activity detection
|
||||
const [vadActive, setVadActive] = useSetting(vadEnabledSetting);
|
||||
|
||||
// Transient suppressor settings
|
||||
const [transientEnabled, setTransientEnabled] = useSetting(transientSuppressorEnabledSetting);
|
||||
const [transientThreshold, setTransientThreshold] = useSetting(transientThresholdSetting);
|
||||
@@ -310,6 +314,31 @@ export const SettingsModal: FC<Props> = ({
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<div className={styles.noiseGateSection}>
|
||||
<Heading
|
||||
type="body"
|
||||
weight="semibold"
|
||||
size="sm"
|
||||
as="h4"
|
||||
className={styles.noiseGateHeading}
|
||||
>
|
||||
Voice Activity Detection
|
||||
</Heading>
|
||||
<Separator className={styles.noiseGateSeparator} />
|
||||
<FieldRow>
|
||||
<InputField
|
||||
id="vadEnabled"
|
||||
type="checkbox"
|
||||
label="Enable voice activity detection"
|
||||
description="Uses the Silero VAD model to mute audio when no speech is detected. Requires the noise gate to be enabled."
|
||||
checked={vadActive}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>): void =>
|
||||
setVadActive(e.target.checked)
|
||||
}
|
||||
disabled={!noiseGateEnabled}
|
||||
/>
|
||||
</FieldRow>
|
||||
</div>
|
||||
<div className={styles.noiseGateSection}>
|
||||
<Heading
|
||||
type="body"
|
||||
|
||||
@@ -145,6 +145,8 @@ export const noiseGateHold = new Setting<number>("noise-gate-hold", 200);
|
||||
// Time in ms for the gate to fully close after hold expires
|
||||
export const noiseGateRelease = new Setting<number>("noise-gate-release", 150);
|
||||
|
||||
export const vadEnabled = new Setting<boolean>("vad-enabled", false);
|
||||
|
||||
export const transientSuppressorEnabled = new Setting<boolean>(
|
||||
"transient-suppressor-enabled",
|
||||
false,
|
||||
|
||||
@@ -41,11 +41,13 @@ import {
|
||||
transientSuppressorEnabled,
|
||||
transientThreshold,
|
||||
transientRelease,
|
||||
vadEnabled,
|
||||
} from "../../../settings/settings.ts";
|
||||
import {
|
||||
type NoiseGateParams,
|
||||
NoiseGateTransformer,
|
||||
} from "../../../livekit/NoiseGateTransformer.ts";
|
||||
import { SileroVADGate } from "../../../livekit/SileroVADGate.ts";
|
||||
import { observeTrackReference$ } from "../../observeTrackReference";
|
||||
import { type Connection } from "../remoteMembers/Connection.ts";
|
||||
import { ObservableScope } from "../../ObservableScope.ts";
|
||||
@@ -435,6 +437,7 @@ export class Publisher {
|
||||
|
||||
let transformer: NoiseGateTransformer | null = null;
|
||||
let audioCtx: AudioContext | null = null;
|
||||
let vadGate: SileroVADGate | null = null;
|
||||
|
||||
const currentParams = (): NoiseGateParams => ({
|
||||
threshold: noiseGateThreshold.getValue(),
|
||||
@@ -446,6 +449,32 @@ export class Publisher {
|
||||
transientReleaseMs: transientRelease.getValue(),
|
||||
});
|
||||
|
||||
const stopVAD = (): void => {
|
||||
if (vadGate) {
|
||||
void vadGate.destroy();
|
||||
vadGate = null;
|
||||
}
|
||||
// Reset gate to open so audio flows if VAD is toggled off mid-call
|
||||
transformer?.setVADOpen(true);
|
||||
};
|
||||
|
||||
const startVAD = (track: LocalAudioTrack, ctx: AudioContext): void => {
|
||||
stopVAD();
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const rawTrack: MediaStreamTrack | undefined = (track as any).mediaStreamTrack;
|
||||
if (!rawTrack) {
|
||||
this.logger.warn("[VAD] no underlying MediaStreamTrack — skipping VAD");
|
||||
return;
|
||||
}
|
||||
const stream = new MediaStream([rawTrack]);
|
||||
vadGate = new SileroVADGate(stream, ctx);
|
||||
vadGate.onSpeechStart = (): void => transformer?.setVADOpen(true);
|
||||
vadGate.onSpeechEnd = (): void => transformer?.setVADOpen(false);
|
||||
vadGate.start().catch((e: unknown) => {
|
||||
this.logger.error("[VAD] failed to start", e);
|
||||
});
|
||||
};
|
||||
|
||||
// Attach / detach processor when enabled state or the track changes.
|
||||
combineLatest([audioTrack$, noiseGateEnabled.value$])
|
||||
.pipe(scope.bind())
|
||||
@@ -459,18 +488,20 @@ export class Publisher {
|
||||
this.logger.info("[NoiseGate] AudioContext state before resume:", audioCtx.state);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(audioTrack as any).setAudioContext(audioCtx);
|
||||
audioCtx.resume().then(() => {
|
||||
audioCtx.resume().then(async () => {
|
||||
this.logger.info("[NoiseGate] AudioContext state after resume:", audioCtx?.state);
|
||||
return audioTrack
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
.setProcessor(transformer as any);
|
||||
}).then(() => {
|
||||
this.logger.info("[NoiseGate] setProcessor resolved");
|
||||
if (vadEnabled.getValue() && audioCtx) startVAD(audioTrack, audioCtx);
|
||||
}).catch((e: unknown) => {
|
||||
this.logger.error("[NoiseGate] setProcessor failed", e);
|
||||
});
|
||||
} else if (!enabled && audioTrack.getProcessor()) {
|
||||
this.logger.info("[NoiseGate] removing processor");
|
||||
stopVAD();
|
||||
void audioTrack.stopProcessor();
|
||||
void audioCtx?.close();
|
||||
audioCtx = null;
|
||||
@@ -482,6 +513,18 @@ export class Publisher {
|
||||
}
|
||||
});
|
||||
|
||||
// Start/stop VAD when its toggle changes.
|
||||
combineLatest([audioTrack$, vadEnabled.value$])
|
||||
.pipe(scope.bind())
|
||||
.subscribe(([audioTrack, enabled]) => {
|
||||
if (!audioTrack || !audioCtx) return;
|
||||
if (enabled) {
|
||||
startVAD(audioTrack, audioCtx);
|
||||
} else {
|
||||
stopVAD();
|
||||
}
|
||||
});
|
||||
|
||||
// Push param changes to the live worklet without recreating the processor.
|
||||
combineLatest([
|
||||
noiseGateThreshold.value$,
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from "vite";
|
||||
import svgrPlugin from "vite-plugin-svgr";
|
||||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy";
|
||||
|
||||
import { codecovVitePlugin } from "@codecov/vite-plugin";
|
||||
import { sentryVitePlugin } from "@sentry/vite-plugin";
|
||||
@@ -35,6 +36,22 @@ export default ({
|
||||
// build time.
|
||||
process.env.VITE_PACKAGE = packageType ?? "full";
|
||||
const plugins: PluginOption[] = [
|
||||
viteStaticCopy({
|
||||
targets: [
|
||||
{
|
||||
src: "node_modules/@ricky0123/vad-web/dist/vad.worklet.bundle.min.js",
|
||||
dest: "vad",
|
||||
},
|
||||
{
|
||||
src: "node_modules/@ricky0123/vad-web/dist/silero_vad_legacy.onnx",
|
||||
dest: "vad",
|
||||
},
|
||||
{
|
||||
src: "node_modules/onnxruntime-web/dist/*.wasm",
|
||||
dest: "vad",
|
||||
},
|
||||
],
|
||||
}),
|
||||
react(),
|
||||
svgrPlugin({
|
||||
svgrOptions: {
|
||||
|
||||
185
yarn.lock
185
yarn.lock
@@ -3841,6 +3841,79 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@protobufjs/aspromise@npm:1.1.2"
|
||||
checksum: 10c0/a83343a468ff5b5ec6bff36fd788a64c839e48a07ff9f4f813564f58caf44d011cd6504ed2147bf34835bd7a7dd2107052af755961c6b098fd8902b4f6500d0f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/base64@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@protobufjs/base64@npm:1.1.2"
|
||||
checksum: 10c0/eec925e681081af190b8ee231f9bad3101e189abbc182ff279da6b531e7dbd2a56f1f306f37a80b1be9e00aa2d271690d08dcc5f326f71c9eed8546675c8caf6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/codegen@npm:^2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "@protobufjs/codegen@npm:2.0.4"
|
||||
checksum: 10c0/26ae337c5659e41f091606d16465bbcc1df1f37cc1ed462438b1f67be0c1e28dfb2ca9f294f39100c52161aef82edf758c95d6d75650a1ddf31f7ddee1440b43
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/eventemitter@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "@protobufjs/eventemitter@npm:1.1.0"
|
||||
checksum: 10c0/1eb0a75180e5206d1033e4138212a8c7089a3d418c6dfa5a6ce42e593a4ae2e5892c4ef7421f38092badba4040ea6a45f0928869989411001d8c1018ea9a6e70
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/fetch@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "@protobufjs/fetch@npm:1.1.0"
|
||||
dependencies:
|
||||
"@protobufjs/aspromise": "npm:^1.1.1"
|
||||
"@protobufjs/inquire": "npm:^1.1.0"
|
||||
checksum: 10c0/cda6a3dc2d50a182c5865b160f72077aac197046600091dbb005dd0a66db9cce3c5eaed6d470ac8ed49d7bcbeef6ee5f0bc288db5ff9a70cbd003e5909065233
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/float@npm:^1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@protobufjs/float@npm:1.0.2"
|
||||
checksum: 10c0/18f2bdede76ffcf0170708af15c9c9db6259b771e6b84c51b06df34a9c339dbbeec267d14ce0bddd20acc142b1d980d983d31434398df7f98eb0c94a0eb79069
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/inquire@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "@protobufjs/inquire@npm:1.1.0"
|
||||
checksum: 10c0/64372482efcba1fb4d166a2664a6395fa978b557803857c9c03500e0ac1013eb4b1aacc9ed851dd5fc22f81583670b4f4431bae186f3373fedcfde863ef5921a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/path@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@protobufjs/path@npm:1.1.2"
|
||||
checksum: 10c0/cece0a938e7f5dfd2fa03f8c14f2f1cf8b0d6e13ac7326ff4c96ea311effd5fb7ae0bba754fbf505312af2e38500250c90e68506b97c02360a43793d88a0d8b4
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/pool@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "@protobufjs/pool@npm:1.1.0"
|
||||
checksum: 10c0/eda2718b7f222ac6e6ad36f758a92ef90d26526026a19f4f17f668f45e0306a5bd734def3f48f51f8134ae0978b6262a5c517c08b115a551756d1a3aadfcf038
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/utf8@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "@protobufjs/utf8@npm:1.1.0"
|
||||
checksum: 10c0/a3fe31fe3fa29aa3349e2e04ee13dc170cc6af7c23d92ad49e3eeaf79b9766264544d3da824dba93b7855bd6a2982fb40032ef40693da98a136d835752beb487
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/number@npm:1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "@radix-ui/number@npm:1.1.1"
|
||||
@@ -5022,6 +5095,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@ricky0123/vad-web@npm:^0.0.30":
|
||||
version: 0.0.30
|
||||
resolution: "@ricky0123/vad-web@npm:0.0.30"
|
||||
dependencies:
|
||||
onnxruntime-web: "npm:^1.17.0"
|
||||
checksum: 10c0/c91e69fb65879d54eb3eeab3cdadca95b9d1fffe3fbecf8c7ab1d59f418b79ad6e1cd0e67df25db26cf286e8fa86e030ce95ee51a749727e344f7c588d689770
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rolldown/pluginutils@npm:1.0.0-beta.27":
|
||||
version: 1.0.0-beta.27
|
||||
resolution: "@rolldown/pluginutils@npm:1.0.0-beta.27"
|
||||
@@ -5840,6 +5922,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:>=13.7.0":
|
||||
version: 25.5.0
|
||||
resolution: "@types/node@npm:25.5.0"
|
||||
dependencies:
|
||||
undici-types: "npm:~7.18.0"
|
||||
checksum: 10c0/70c508165b6758c4f88d4f91abca526c3985eee1985503d4c2bd994dbaf588e52ac57e571160f18f117d76e963570ac82bd20e743c18987e82564312b3b62119
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/node@npm:^24.0.0":
|
||||
version: 24.10.13
|
||||
resolution: "@types/node@npm:24.10.13"
|
||||
@@ -7387,7 +7478,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"chokidar@npm:^3.5.3":
|
||||
"chokidar@npm:^3.5.3, chokidar@npm:^3.6.0":
|
||||
version: 3.6.0
|
||||
resolution: "chokidar@npm:3.6.0"
|
||||
dependencies:
|
||||
@@ -8303,6 +8394,7 @@ __metadata:
|
||||
"@radix-ui/react-slider": "npm:^1.1.2"
|
||||
"@radix-ui/react-visually-hidden": "npm:^1.0.3"
|
||||
"@react-spring/web": "npm:^10.0.0"
|
||||
"@ricky0123/vad-web": "npm:^0.0.30"
|
||||
"@sentry/react": "npm:^8.0.0"
|
||||
"@sentry/vite-plugin": "npm:^3.0.0"
|
||||
"@stylistic/eslint-plugin": "npm:^3.0.0"
|
||||
@@ -8380,6 +8472,7 @@ __metadata:
|
||||
vite-plugin-generate-file: "npm:^0.3.0"
|
||||
vite-plugin-html: "npm:^3.2.2"
|
||||
vite-plugin-node-stdlib-browser: "npm:^0.2.1"
|
||||
vite-plugin-static-copy: "npm:^4.0.0"
|
||||
vite-plugin-svgr: "npm:^4.0.0"
|
||||
vitest: "npm:^4.0.18"
|
||||
vitest-axe: "npm:^1.0.0-pre.3"
|
||||
@@ -9542,6 +9635,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"flatbuffers@npm:^25.1.24":
|
||||
version: 25.9.23
|
||||
resolution: "flatbuffers@npm:25.9.23"
|
||||
checksum: 10c0/957c4ae2a02be1703c98b36b4dc8ceb81613cf8e2333026afc95a7b68b088bed5458056dc29d0ab7ce8bc403b8c003732b0968d24aba46f5e7c8f71789a6bd9e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"flatted@npm:^3.2.9":
|
||||
version: 3.3.1
|
||||
resolution: "flatted@npm:3.3.1"
|
||||
@@ -9958,6 +10058,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"guid-typescript@npm:^1.0.9":
|
||||
version: 1.0.9
|
||||
resolution: "guid-typescript@npm:1.0.9"
|
||||
checksum: 10c0/fa0a2b2b4e06e0976a81c947b74e114b92f6647e84b52e24ab0981d2fdbaa1a640641d8fd269004dd7c581baebeb4f9d9782b74391e717e47c9b822bea4b3be6
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"gulp-sort@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "gulp-sort@npm:2.0.0"
|
||||
@@ -11228,6 +11335,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"long@npm:^5.0.0, long@npm:^5.2.3":
|
||||
version: 5.3.2
|
||||
resolution: "long@npm:5.3.2"
|
||||
checksum: 10c0/7130fe1cbce2dca06734b35b70d380ca3f70271c7f8852c922a7c62c86c4e35f0c39290565eca7133c625908d40e126ac57c02b1b1a4636b9457d77e1e60b981
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"loose-envify@npm:^1.4.0":
|
||||
version: 1.4.0
|
||||
resolution: "loose-envify@npm:1.4.0"
|
||||
@@ -11932,6 +12046,27 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"onnxruntime-common@npm:1.24.3":
|
||||
version: 1.24.3
|
||||
resolution: "onnxruntime-common@npm:1.24.3"
|
||||
checksum: 10c0/3160a08a8addf7b1c8f2ff0c12c126c84847d5b36f8c047cf05560d05faf7605fe4c3366c725cfbd305d4399d0930c632a22bd6a600488ac2c6f9ee3e2aebe25
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"onnxruntime-web@npm:^1.17.0":
|
||||
version: 1.24.3
|
||||
resolution: "onnxruntime-web@npm:1.24.3"
|
||||
dependencies:
|
||||
flatbuffers: "npm:^25.1.24"
|
||||
guid-typescript: "npm:^1.0.9"
|
||||
long: "npm:^5.2.3"
|
||||
onnxruntime-common: "npm:1.24.3"
|
||||
platform: "npm:^1.3.6"
|
||||
protobufjs: "npm:^7.2.4"
|
||||
checksum: 10c0/7975ad03fed7017a84b64e8038187dc52ec383628fd4ac380a9dee628c1aee7959f8398c0ffe3e503b4565d381d9f8ef8863f942386f56ff5ee0915e38f828c3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"optionator@npm:^0.9.3":
|
||||
version: 0.9.4
|
||||
resolution: "optionator@npm:0.9.4"
|
||||
@@ -12076,6 +12211,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-map@npm:^7.0.4":
|
||||
version: 7.0.4
|
||||
resolution: "p-map@npm:7.0.4"
|
||||
checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"p-retry@npm:7":
|
||||
version: 7.0.0
|
||||
resolution: "p-retry@npm:7.0.0"
|
||||
@@ -12328,6 +12470,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"platform@npm:^1.3.6":
|
||||
version: 1.3.6
|
||||
resolution: "platform@npm:1.3.6"
|
||||
checksum: 10c0/69f2eb692e15f1a343dd0d9347babd9ca933824c8673096be746ff66f99f2bdc909fadd8609076132e6ec768349080babb7362299f2a7f885b98f1254ae6224b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"playwright-core@npm:1.58.2":
|
||||
version: 1.58.2
|
||||
resolution: "playwright-core@npm:1.58.2"
|
||||
@@ -12883,6 +13032,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"protobufjs@npm:^7.2.4":
|
||||
version: 7.5.4
|
||||
resolution: "protobufjs@npm:7.5.4"
|
||||
dependencies:
|
||||
"@protobufjs/aspromise": "npm:^1.1.2"
|
||||
"@protobufjs/base64": "npm:^1.1.2"
|
||||
"@protobufjs/codegen": "npm:^2.0.4"
|
||||
"@protobufjs/eventemitter": "npm:^1.1.0"
|
||||
"@protobufjs/fetch": "npm:^1.1.0"
|
||||
"@protobufjs/float": "npm:^1.0.2"
|
||||
"@protobufjs/inquire": "npm:^1.1.0"
|
||||
"@protobufjs/path": "npm:^1.1.2"
|
||||
"@protobufjs/pool": "npm:^1.1.0"
|
||||
"@protobufjs/utf8": "npm:^1.1.0"
|
||||
"@types/node": "npm:>=13.7.0"
|
||||
long: "npm:^5.0.0"
|
||||
checksum: 10c0/913b676109ffb3c05d3d31e03a684e569be91f3bba8613da4a683d69d9dba948daa2afd7d2e7944d1aa6c417890c35d9d9a8883c1160affafb0f9670d59ef722
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"proxy-from-env@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "proxy-from-env@npm:1.1.0"
|
||||
@@ -15337,6 +15506,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-plugin-static-copy@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "vite-plugin-static-copy@npm:4.0.0"
|
||||
dependencies:
|
||||
chokidar: "npm:^3.6.0"
|
||||
p-map: "npm:^7.0.4"
|
||||
picocolors: "npm:^1.1.1"
|
||||
tinyglobby: "npm:^0.2.15"
|
||||
peerDependencies:
|
||||
vite: ^6.0.0 || ^7.0.0 || ^8.0.0
|
||||
checksum: 10c0/05b42b6f942e81b838f828c596fc6d00f72c0b5e1c4d68df13aaa4405c96d71333a082cc1bba96d0153134191addff8b2fe9134ed2e725b3b808e3b8470497c8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite-plugin-svgr@npm:^4.0.0":
|
||||
version: 4.5.0
|
||||
resolution: "vite-plugin-svgr@npm:4.5.0"
|
||||
|
||||
Reference in New Issue
Block a user