This commit is contained in:
2026-02-23 11:16:33 +00:00
parent 2779fe22c6
commit 8fb96c7cf8
23 changed files with 575 additions and 102 deletions
+40
View File
@@ -2,6 +2,7 @@ import type { Context } from 'hono';
import { createRouter } from '../../create-router';
import * as storage from './storage';
import { readApiKeys, readLocalProviders } from '../server-settings/pi-mono';
import { readSttConfig } from '../server-settings/stt';
import { listPiModels } from './list-models';
import { getHomeDir } from '../../data-path';
import { resolveBaseCwd } from './websocket';
@@ -497,3 +498,42 @@ piRestRouter.post('/pi/sessions/:sessionId/move', async (ctx: Context) => {
return ctx.json({ error: 'Failed to move session' }, 500);
}
});
/**
* POST /api/pi/stt
* Proxy audio to configured Whisper server for speech-to-text transcription.
* Accepts multipart form data with audio file + whisper params.
*/
piRestRouter.post('/pi/stt', async (ctx: Context) => {
const sttConfig = await readSttConfig();
if (!sttConfig?.url) {
return ctx.json({ error: 'Whisper not configured — set it up in Settings → Speech to Text' }, 400);
}
const body = await ctx.req.parseBody();
const file = body['file'];
if (!file || !(file instanceof File)) {
return ctx.json({ error: 'file is required' }, 400);
}
const formData = new FormData();
formData.append('file', file, 'recording.wav');
formData.append('temperature', String(body['temperature'] ?? '0.0'));
formData.append('temperature_inc', String(body['temperature_inc'] ?? '0.2'));
formData.append('response_format', String(body['response_format'] ?? 'json'));
try {
const res = await fetch(`${sttConfig.url.replace(/\/+$/, '')}/inference`, {
method: 'POST',
body: formData,
});
if (!res.ok) {
return ctx.json({ error: `Whisper returned ${res.status}` }, 502);
}
const json = await res.json();
return ctx.json(json);
} catch (err) {
logger.error('STT proxy failed', { error: String(err) });
return ctx.json({ error: 'Failed to reach Whisper server' }, 502);
}
});