## Что сделано - `DEFAULTS.whisperPrompt` изменён с 107-символьного английского списка терминов на пустую строку (`src/config.ts:8`). Английский промпт уводил русский аудио в английский (особенно на turbo) — нарушает документацию Groq: «Use the same language as the language of the audio file». - `tests/config.test.ts` — 2 устаревших теста (`non-empty whisperPrompt`, `under 120 characters`) заменены на 1: `should have empty whisperPrompt by default`. - Version bump 1.0.4 → 1.0.5 в `vite.config.ts:11` и `package.json:3`. - ADR-0007 (`docs/decisions/0007-pr-46-empty-whisper-prompt.md`) — фиксирует решение, контекст (PR #43 + баг), последствия (`buildFormData` falsy-check), альтернативы (двуязычный промпт, смена модели — обе отвергнуты). - README — секция troubleshooting «Wrong Language (English instead of Russian)» добавлена в EN и RU секции после температурного блока. Инструкция очистить Whisper Prompt через меню Tampermonkey. ## Почему PR #43 добавил английский biasing-промпт для технических терминов. На практике английский промпт + русский аудио = модель возвращает английский текст, перебивая явный `language=ru`. Пользователь подтвердил баг на turbo. Параметр `prompt` Whisper — это seed-контекст декодера, модель стремится продолжить его язык. Пустой default = чистый auto-detect без biasing. Поле и menu command остаются для юзеров с узкопрофильной терминологией. ## Watch out - **Обратная совместимость**: существующие юзеры со старым 107-символьным значением в `GM_getValue("whisperPrompt")` сохраняют его — новый default применяется только к свежим установкам и к тем, кто очистил поле через `Set Whisper Prompt`. Миграции нет намеренно (не ломаем сохранённые настройки). - `buildFormData` использует falsy-check `if (config.whisperPrompt)` — пустая строка не отправляет поле `prompt` в Groq API вообще. - `transcribe.test.ts` использует mock `whisperPrompt: "Software development discussion."` — валидный mock для тестирования prompt-передачи, НЕ тронут (не путать с DEFAULTS). - `DEFAULTS.model` (`whisper-large-v3`), `DEFAULTS.language` (`""`), `DEFAULTS.temperature` (`0`), `DEFAULTS.endpoint` — не менялись. Смена модели на turbo была альтернативой, отвергнута (v3 лучше для русского, баг в промпте не в модели). - Touchpoints ровно 7: `src/config.ts`, `tests/config.test.ts`, `vite.config.ts`, `package.json`, `docs/decisions/0007-*.md` (новый), `README.md` (2 вставки EN+RU). `src/transcribe.ts` и остальные src-файлы не тронуты. ## Pending - CI на push-ветке (vitest, biome, tsc, knip) — все зелёные локально (55/55 tests, 22 файла biome-clean, tsc чист, knip чист). - После merge — ADR-0007 ссылается на PR #46 (номер уже известен из issue). Closes #46 --------- Co-authored-by: opencode-agent <agent@opencode.local>
125 lines
3.5 KiB
TypeScript
125 lines
3.5 KiB
TypeScript
import { describe, expect, it, vi } from "vitest";
|
|
|
|
vi.mock("$", () => ({
|
|
GM_getValue: vi.fn((key: string, defaultValue: unknown) => defaultValue),
|
|
GM_setValue: vi.fn(),
|
|
GM_registerMenuCommand: vi.fn(),
|
|
GM_xmlhttpRequest: vi.fn(),
|
|
}));
|
|
|
|
import { GM_getValue, GM_registerMenuCommand, GM_setValue } from "$";
|
|
import {
|
|
DEFAULTS,
|
|
getConfig,
|
|
isFirstRun,
|
|
registerMenuCommands,
|
|
setConfig,
|
|
validateApiKey,
|
|
} from "../src/config.js";
|
|
|
|
describe("DEFAULTS", () => {
|
|
it("should have whisper-large-v3 as default model", () => {
|
|
expect(DEFAULTS.model).toBe("whisper-large-v3");
|
|
});
|
|
|
|
it("should have empty language for auto-detect", () => {
|
|
expect(DEFAULTS.language).toBe("");
|
|
});
|
|
|
|
it("should have empty whisperPrompt by default", () => {
|
|
expect(DEFAULTS.whisperPrompt).toBe("");
|
|
});
|
|
|
|
it("should have autoSubmit disabled by default", () => {
|
|
expect(DEFAULTS.autoSubmit).toBe(false);
|
|
});
|
|
|
|
it("should have default Groq endpoint", () => {
|
|
expect(DEFAULTS.endpoint).toBe("https://api.groq.com/openai/v1/audio/transcriptions");
|
|
});
|
|
|
|
it("should have temperature 0 by default", () => {
|
|
expect(DEFAULTS.temperature).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("validateApiKey", () => {
|
|
it("should accept valid key with gsk_ prefix", () => {
|
|
expect(validateApiKey("gsk_test_fake_key_1234567890abcdef")).toBe(true);
|
|
});
|
|
|
|
it("should reject key without gsk_ prefix", () => {
|
|
expect(validateApiKey("sk_test_key_12345")).toBe(false);
|
|
});
|
|
|
|
it("should reject key that is too short", () => {
|
|
expect(validateApiKey("gsk_short")).toBe(false);
|
|
});
|
|
|
|
it("should reject empty string", () => {
|
|
expect(validateApiKey("")).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("getConfig", () => {
|
|
it("should return defaults when GM storage is empty", () => {
|
|
vi.mocked(GM_getValue).mockImplementation((key: string, def: unknown) => def);
|
|
|
|
const config = getConfig();
|
|
expect(config.model).toBe(DEFAULTS.model);
|
|
expect(config.language).toBe(DEFAULTS.language);
|
|
expect(config.groqApiKey).toBe("");
|
|
});
|
|
|
|
it("should return stored values when present", () => {
|
|
vi.mocked(GM_getValue).mockImplementation((key: string, def: unknown) => {
|
|
if (key === "groqApiKey") {
|
|
return "gsk_stored_key";
|
|
}
|
|
if (key === "model") {
|
|
return "whisper-large-v3-turbo";
|
|
}
|
|
return def;
|
|
});
|
|
|
|
const config = getConfig();
|
|
expect(config.groqApiKey).toBe("gsk_stored_key");
|
|
expect(config.model).toBe("whisper-large-v3-turbo");
|
|
});
|
|
});
|
|
|
|
describe("isFirstRun", () => {
|
|
it("should return true when no API key stored", () => {
|
|
vi.mocked(GM_getValue).mockReturnValue("");
|
|
expect(isFirstRun()).toBe(true);
|
|
});
|
|
|
|
it("should return false when API key is stored", () => {
|
|
vi.mocked(GM_getValue).mockReturnValue("gsk_stored_key");
|
|
expect(isFirstRun()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe("setConfig", () => {
|
|
it("should call GM_setValue for each key", () => {
|
|
setConfig({ groqApiKey: "gsk_new", model: "whisper-large-v3-turbo" });
|
|
expect(GM_setValue).toHaveBeenCalledWith("groqApiKey", "gsk_new");
|
|
expect(GM_setValue).toHaveBeenCalledWith("model", "whisper-large-v3-turbo");
|
|
});
|
|
});
|
|
|
|
describe("registerMenuCommands", () => {
|
|
it("should register all menu commands", () => {
|
|
const callbacks = {
|
|
onSetKey: () => {},
|
|
onToggleAutoSubmit: () => {},
|
|
onSetModel: () => {},
|
|
onSetLanguage: () => {},
|
|
onSetPrompt: () => {},
|
|
onSetEndpoint: () => {},
|
|
onSetTemperature: () => {},
|
|
};
|
|
registerMenuCommands(callbacks);
|
|
expect(GM_registerMenuCommand).toHaveBeenCalledTimes(7);
|
|
});
|
|
});
|