SvelteKit
Install
Install the package
npm install @transcribe/transcriber
and copy the files from @transcribe/shout
to /public
cp -r node_modules/@transcribe/shout/src/shout/* static/
Cross-Origin Headers
The wasm files must be served with the correct Cross-Origin headers. Otherwise browsers will refuse to load the files.
For the development server the headers are added by a "plugin" in vite.config.ts
.
// vite.config.ts
// ...
export default defineConfig({
plugins: [
{
name: "configure-response-headers",
configureServer(server) {
server.middlewares.use((req, res, next) => {
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
next();
});
},
},
sveltekit(),
],
// ...
});
For the preview server you can use the adapter-node
in combination with a custom server that adds the headers.
// server.js
// ...
app.use((req, res, next) => {
res.setHeader("Cross-Origin-Opener-Policy", "same-origin");
res.setHeader("Cross-Origin-Embedder-Policy", "require-corp");
next();
});
// ...
Depending on your deployment target you need to make sure that the webserver sets the correct headers for shout.wasm.js
and shout.wasm.worker.mjs
.
Usage
Rollup is not able to bundle shout.wasm.js
. Also using an importmap
like in Svelte doesn't work. To work around this we use a dynamic import that loads the module from /static/shout.wasm.js
.
First exclude shout.wasm.js
from the bundler in vite.config.ts
// vite.config.ts
// ...
export default defineConfig({
// ...
build: {
rollupOptions: {
external: ["/shout.wasm.js?url"],
},
},
});
then use dynamic import("/shout.wasm.js?url")
in the component
// +page.svelte
<script lang="ts">
import { onMount } from "svelte";
import { FileTranscriber } from "@transcribe/transcriber";
let createModule: (args?: {}) => Promise<any>;
let transcriber: FileTranscriber;
async function transcribe() {
if (!createModule) {
console.error("WASM module not loaded yet");
return;
}
// check if transcriber is initialized
if (!transcriber?.isReady) return;
// there must be at least one user interaction (e.g click) before you can call this function
const result = await transcriber.transcribe("/jfk.wav", { lang: "en" });
// do something with the result json
this.result = result.transcription.map((t) => t.text).join(" ");
}
onMount(async () => {
// dynamic import wasm module from /static
// this is a workaround because Rollup can't bundle this file
createModule = (await import("/shout.wasm.js?url")).default;
// create new instance
transcriber = new FileTranscriber({
createModule,
model: "/ggml-tiny-q5_1.bin",
workerPath: "/",
});
// and initialize the transcriber
await transcriber.init();
});
</script>
Note: Transcribe.js only runs in the browser. Node.js is not supported. Make sure that the code only gets executed in browser context and on/after user interaction.