Add local Whisper speech input
This commit is contained in:
88
tools/stt-server.mjs
Normal file
88
tools/stt-server.mjs
Normal file
@@ -0,0 +1,88 @@
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import cors from 'cors';
|
||||
import express from 'express';
|
||||
import multer from 'multer';
|
||||
import { nodewhisper } from 'nodejs-whisper';
|
||||
|
||||
const app = express();
|
||||
const port = Number(process.env.STT_PORT ?? 3334);
|
||||
const host = process.env.STT_HOST ?? '0.0.0.0';
|
||||
const uploadDir = path.resolve(process.cwd(), '.stt-uploads');
|
||||
const modelRootPath = path.resolve(process.cwd(), '.whisper-models');
|
||||
const modelName = process.env.STT_MODEL ?? 'tiny.en';
|
||||
|
||||
fs.mkdirSync(uploadDir, { recursive: true });
|
||||
fs.mkdirSync(modelRootPath, { recursive: true });
|
||||
|
||||
const upload = multer({ dest: uploadDir });
|
||||
|
||||
app.use(cors());
|
||||
|
||||
app.get('/health', (_request, response) => {
|
||||
response.json({ ok: true, model: modelName });
|
||||
});
|
||||
|
||||
app.post('/transcribe', upload.single('audio'), async (request, response) => {
|
||||
if (!request.file) {
|
||||
response.status(400).json({ error: 'Missing audio file' });
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const text = await nodewhisper(request.file.path, {
|
||||
modelName,
|
||||
autoDownloadModelName: modelName,
|
||||
modelRootPath,
|
||||
removeWavFileAfterTranscription: true,
|
||||
withCuda: false,
|
||||
logger: quietLogger,
|
||||
whisperOptions: {
|
||||
outputInText: false,
|
||||
outputInSrt: false,
|
||||
outputInVtt: false,
|
||||
outputInCsv: false,
|
||||
outputInJson: false,
|
||||
outputInJsonFull: false,
|
||||
outputInLrc: false,
|
||||
outputInWords: false,
|
||||
translateToEnglish: false,
|
||||
splitOnWord: true,
|
||||
noGpu: true,
|
||||
},
|
||||
});
|
||||
|
||||
response.json({ text: cleanTranscript(text) });
|
||||
} catch (error) {
|
||||
response.status(500).json({ error: error instanceof Error ? error.message : String(error) });
|
||||
} finally {
|
||||
safeUnlink(request.file.path);
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(port, host, () => {
|
||||
console.log(`STT server listening on http://${host}:${port}`);
|
||||
console.log(`Whisper model: ${modelName}`);
|
||||
});
|
||||
|
||||
const quietLogger = {
|
||||
debug: () => undefined,
|
||||
info: () => undefined,
|
||||
log: () => undefined,
|
||||
warn: console.warn,
|
||||
error: console.error,
|
||||
};
|
||||
|
||||
function cleanTranscript(value) {
|
||||
return String(value)
|
||||
.replace(/\[[^\]]*\]/g, ' ')
|
||||
.replace(/\([^)]*\)/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function safeUnlink(filePath) {
|
||||
if (filePath && fs.existsSync(filePath)) {
|
||||
fs.unlinkSync(filePath);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user