Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions samples/whisper-speech-to-text/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules/
*.wasm
build/
dist/
7 changes: 7 additions & 0 deletions samples/whisper-speech-to-text/captions/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
node_modules
dist
target
.spin/
build/
.spin
.spin-aka
1 change: 1 addition & 0 deletions samples/whisper-speech-to-text/captions/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
KNITWIT_SOURCE=./config/knitwit.json
14 changes: 14 additions & 0 deletions samples/whisper-speech-to-text/captions/config/knitwit.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"version": 1,
"project": {
"worlds": [
"spin-http"
]
},
"packages": {
"@fermyon/spin-sdk": {
"witPath": "../../bin/wit",
"world": "spin-imports"
}
}
}
3,488 changes: 3,488 additions & 0 deletions samples/whisper-speech-to-text/captions/package-lock.json

Large diffs are not rendered by default.

25 changes: 25 additions & 0 deletions samples/whisper-speech-to-text/captions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "captions",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "knitwit --out-dir build/wit/knitwit --out-world combined && npx webpack --mode=production && npx mkdirp dist && npx j2w -i build/bundle.js -d build/wit/knitwit -n combined -o dist/captions.wasm",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"mkdirp": "^3.0.1",
"ts-loader": "^9.4.1",
"typescript": "^4.8.4",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"@fermyon/knitwit": "0.3.0"
},
"dependencies": {
"@fermyon/spin-sdk": "3.2.0",
"itty-router": "^5.0.18"
}
}
59 changes: 59 additions & 0 deletions samples/whisper-speech-to-text/captions/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Variables } from '@fermyon/spin-sdk';
import { AutoRouter as Router } from 'itty-router';

let router = Router();


// Helper function to create form data with audio blob in the
// format required by the transcription API.
//
// This is compatible with the OpenAI Whisper API.
function createFormData(audioBlob: ArrayBuffer): FormData {
const formData = new FormData();
formData.append('model', 'whisper-1');
formData.append('file', new Blob([audioBlob], { type: 'audio/wav' }), 'audio.wav');
formData.append('stream', 'false');
formData.append('response_format', 'json');

return formData;
};

// Main transcription endpoint
router.post('/api/transcribe', async (request: Request) => {
try {
console.log('Received request:', request);
// Get raw audio data from request body
const audioData = await request.arrayBuffer();
console.log(`Received audio data of size ${audioData.byteLength}`);

if (!audioData || audioData.byteLength === 0) {
return new Response(JSON.stringify({ error: 'No audio data provided' }), { status: 400 });
}

// Create form data for the transcription API
const formData = createFormData(audioData);

// Send request to transcription API
const transcriptionResponse = await fetch(Variables.get('transcription_api')!, {
method: 'POST',
body: formData
});

if (!transcriptionResponse.ok) {
throw new Error(`Transcription API error: ${transcriptionResponse.status}`);
}

const transcription = await transcriptionResponse.json();

return new Response(JSON.stringify({
text: transcription.text,
segments: transcription.segments
}));
} catch (error) {
console.error('Transcription error:', error);
return new Response(JSON.stringify({ error: 'Internal server error' }), { status: 500 });
}
});

//@ts-ignore
addEventListener('fetch', async (event: FetchEvent) => { event.respondWith(router.fetch(event.request, { event })) });
18 changes: 18 additions & 0 deletions samples/whisper-speech-to-text/captions/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"compilerOptions": {
"outDir": "./dist/",
"noImplicitAny": true,
"module": "es6",
"target": "es2020",
"jsx": "react",
"skipLibCheck": true,
"lib": [
"ES2020",
"WebWorker"
],
"allowJs": true,
"strict": true,
"noImplicitReturns": true,
"moduleResolution": "node"
}
}
38 changes: 38 additions & 0 deletions samples/whisper-speech-to-text/captions/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const path = require('path');
const SpinSdkPlugin = require("@fermyon/spin-sdk/plugins/webpack")

module.exports = {
entry: './src/index.ts',
experiments: {
outputModule: true,
},
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
path: path.resolve(__dirname, './build'),
filename: 'bundle.js',
module: true,
library: {
type: "module",
}
},
plugins: [
new SpinSdkPlugin()
],
optimization: {
minimize: false
},
performance: {
hints: false,
}
};
Loading