feat: add preferred STT languages and fix model settings layout

This commit is contained in:
2026-10-26 02:14:27 +03:00
parent 70977bad84
commit ce28d95bcf
13 changed files with 195 additions and 50 deletions
+30
View File
@@ -7,6 +7,7 @@ import { createTeacherAgent } from "../src/agent/teacher-agent.ts";
import { createPracticeAgent } from "../src/agent/teacher-agent.ts";
import { sanitizeUserSettings } from "../src/core/settings.ts";
import { parseGeneralSettingsBody } from "../src/server/settings-body.ts";
import { resolveSettings } from "../src/core/settings-resolution.ts";
import { countLabel, dictationUrl, resolveLanguage, resolveSttLanguage, systemLanguage, translate } from "../src/core/i18n.ts";
import { sessionMarkdown } from "../src/core/session-markdown.ts";
import type { LhMessage } from "../src/core/native-messages.ts";
@@ -68,6 +69,35 @@ describe("language preferences", () => {
});
}
});
it("validates and resolves preferred speech languages without changing the recognition mode", () => {
const general = { language: "ru", sttLanguage: "multi", sttPreferredLanguages: ["ru", "en", "ru"], autoUpdate: false };
const expected = { ...general, sttPreferredLanguages: ["ru", "en"] };
const parsed = parseGeneralSettingsBody(general);
assert.deepEqual(parsed, { ok: true, settings: expected });
const record = sanitizeUserSettings({ version: 1, general });
assert.deepEqual(record?.general, expected);
assert.deepEqual(resolveSettings(record).general, expected);
assert.deepEqual(parseGeneralSettingsBody({ sttPreferredLanguages: [] }), { ok: true, settings: { sttPreferredLanguages: [] } });
for (const invalid of [null, "en", ["de"], ["multi"], ["en", 1], {}]) {
const result = parseGeneralSettingsBody({ sttPreferredLanguages: invalid });
assert(!result.ok);
assert.equal(translate("ru", result.error), "Предпочитаемые языки должны быть списком кодов «en» и «ru»");
}
assert.deepEqual(sanitizeUserSettings({ version: 1, general: { sttPreferredLanguages: ["ru", "de", "en", null, "ru"] } })?.general, { sttPreferredLanguages: ["ru", "en"] });
assert.deepEqual(sanitizeUserSettings({ version: 1, general: { sttPreferredLanguages: "ru" } })?.general, {});
});
it("sends repeated language hints only for multilingual recognition, with no hints by default", () => {
assert.deepEqual(new URL(dictationUrl("multi")).searchParams.getAll("language_hint"), []);
assert.deepEqual(new URL(dictationUrl("multi", [])).searchParams.getAll("language_hint"), []);
const url = new URL(dictationUrl("multi", ["en", "ru", "en"]));
assert.deepEqual(url.searchParams.getAll("language_hint"), ["en", "ru"]);
assert.equal(url.searchParams.get("language"), "multi");
url.searchParams.delete("language_hint");
assert.equal(url.toString(), dictationUrl("multi"), "hinting must preserve every existing streaming parameter");
for (const language of ["en", "ru"] as const) {
assert.equal(dictationUrl(language, ["en", "ru"]), dictationUrl(language));
}
});
});
describe("translation quality and rendering", () => {