Let admins hear a voice sample before picking it

The Speech section of every model settings form now has "Hear a
sample", which streams a short sentence (AppData.VoicePreviewText) in
the form's model and voice before they're saved, through
GET api/admin/harness/preview-voice (super admins and admins, that
model only via grabModelCandidate). pickVoice is shared with
speakText, and explainAudioError reads why a streamed player failed
for both read-aloud and the sample.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-19 21:32:49 +01:00
co-authored by Claude Opus 5.5
parent 148d02dcfe
commit bc499a7466
10 changed files with 278 additions and 29 deletions
@@ -0,0 +1,63 @@
import BunSQLite from "@moduletrace/bun-sqlite";
import type { BUN_SQLITE_COBBLE_HARNESS_MODELS } from "@/db/types/db";
import type { HarnessKind } from "@/src/dict/harness-dict";
import modelServesHarness from "@/src/harness/catalog/model-serves-harness";
import type { HarnessCandidate } from "@/src/harness/types";
import AppError from "@/src/utils/app-error";
import grabHarnessProviders from "./grab-harness-providers";
import harnessModelRowToCatalog from "./harness-model-row-to-catalog";
import resolveProviderConfig from "./resolve-provider-config";
type Params = {
model_id: number;
harness: HarnessKind;
};
/**
* One catalog model as a candidate to call directly, whatever is saved
* (e.g. to try it before picking it). Throws when it's gone, can't do the
* harness's job, or its provider is off or has no usable key.
*/
export default async function grabModelCandidate({
model_id,
harness,
}: Params): Promise<HarnessCandidate> {
const row = (
await BunSQLite.sql<BUN_SQLITE_COBBLE_HARNESS_MODELS>({
sql: `SELECT * FROM harness_models WHERE id = ? AND available = 1`,
values: [model_id],
})
).payload?.[0];
if (!row?.provider_id) {
throw new AppError(`That model isn't available any more.`);
}
const model = harnessModelRowToCatalog({ row });
if (!modelServesHarness({ model, harness })) {
throw new AppError(`That model can't do this.`);
}
const [provider] = await grabHarnessProviders({
provider_id: row.provider_id,
enabled_only: true,
});
if (!provider) {
throw new AppError(`That model's provider is turned off.`);
}
const { config, usable } = await resolveProviderConfig({ provider });
if (!usable) {
throw new AppError(`That model's provider has no usable key.`);
}
return {
key: `${row.provider_id}:${model.slug}`,
provider: config,
model,
source: "pinned",
};
}