opencode-voice-dictation/vite.config.ts
Sergey c074dfd777
feat(transcription): custom endpoint and temperature (#43)
## Что сделано

- `src/types.ts`: добавлены поля `endpoint: string` и `temperature:
number` в интерфейс `AppConfig`.
- `src/config.ts`:
- `DEFAULTS.endpoint =
"https://api.groq.com/openai/v1/audio/transcriptions"` (обратная
совместимость).
  - `DEFAULTS.temperature = 0` (детерминированный вывод).
- `DEFAULTS.whisperPrompt` сокращён с ~270 до 107 символов — термины
через запятую, без предложений.
- `getConfig()` читает новые поля через `GM_getValue` с fallback на
`DEFAULTS`.
- Добавлены 2 меню-команды: «Set STT Endpoint» и «Set Temperature» в
`registerMenuCommands` (параметры `onSetEndpoint`, `onSetTemperature`).
- `src/index.ts`: реализованы `promptForEndpoint` (fallback на дефолт
при пустом вводе) и `promptForTemperature` (clamp к `[0, 1]`,
NaN-валидация, сохранение текущего значения при cancel),
зарегистрированы в `registerMenuCommands`.
- `src/transcribe.ts`: удалён хардкод `GROQ_API_URL`, используется
`config.endpoint`; в `buildFormData` добавлено
`formData.append("temperature", String(config.temperature))`.
- `vite.config.ts`: `@connect api.groq.com` → `@connect *` (разрешает
`GM_xmlhttpRequest` к любому домену).
- `README.md`: добавлены разделы «Custom STT Endpoint» (EN+RU) с
примером nginx `proxy_pass` и «Temperature».
- `tests/`: обновлены `mockConfig` (новые поля), ассерты на
`temperature` в FormData, тест на длину `whisperPrompt < 120`,
`registerMenuCommands` теперь ожидает 7 команд.

## Почему

Groq периодически блокирует прямые IP-запросы к `api.groq.com` — нужен
обход через пользовательский nginx-прокси (свой endpoint). Whisper
галлюцинирует на тишине/шуме — `temperature=0` снижает галлюцинации.
Длинный `whisperPrompt` с целыми предложениями мог «утекать» в вывод
транскрипции — сокращён до списка терминов через запятую (~107
символов). Хардкод `GROQ_API_URL` и `@connect api.groq.com` блокировали
использование кастомных доменов.

## Watch out

- `@connect *` в метаблоке расширяет поверхность запросов userscript-а
на любой домен — юзер должен доверять установленному endpoint. Это
намеренный trade-off для поддержки произвольных прокси.
- Существующие юзеры со старым `whisperPrompt` в `GM_getValue` сохраняют
своё значение (новый короткий default применяется только если ключ не
задан) — обратная совместимость сохранена.
- Кламп температуры: ввод `NaN` → toast «Invalid temperature» (значение
не меняется); ввод `5` → `1`; ввод `-0.3` → `0`.
- Пустой endpoint (юзер ввёл пробелы) → fallback на `DEFAULTS.endpoint`
(`api.groq.com`), не пустая строка.
- Cancel в prompt (Esc) по endpoint/temperature → значение не меняется
(поведение `null`-check).
- Error-сообщения `transcribe.ts` всё ещё упоминают «Groq API» —
оставлено намеренно, т.к. дефолтный endpoint = Groq и большинство юзеров
используют его.

## Pending

- Обновить `@version` в `vite.config.ts` при релизе (сейчас `1.0.3` — не
тронуто, решает релиз-процесс).
- Trim тишины (RMS-based) — явно вне scope этого issue (отдельный PR
если `temperature=0` не поможет).

Closes #42

Closes #42

---------

Co-authored-by: opencode-agent <agent@opencode.local>
2026-08-04 12:32:39 +03:00

31 lines
1.1 KiB
TypeScript

import { defineConfig } from "vite";
import monkey from "vite-plugin-monkey";
export default defineConfig({
plugins: [
monkey({
entry: "src/index.ts",
userscript: {
name: "OpenCode Voice Dictation",
namespace: "https://github.com/slaid098/opencode-voice-dictation",
version: "1.0.3",
description:
"Voice dictation for OpenCode web using Whisper (Groq API) - works on PC and mobile",
author: "slaid098",
match: ["*://*/*"],
grant: ["GM_xmlhttpRequest", "GM_getValue", "GM_setValue", "GM_registerMenuCommand"],
connect: ["*"],
"run-at": "document-idle",
icon: "https://raw.githubusercontent.com/slaid098/opencode-voice-dictation/main/assets/icon.png",
updateURL:
"https://raw.githubusercontent.com/slaid098/opencode-voice-dictation/dist/opencode-voice-dictation.meta.js",
downloadURL:
"https://raw.githubusercontent.com/slaid098/opencode-voice-dictation/dist/opencode-voice-dictation.user.js",
},
build: {
fileName: "opencode-voice-dictation.user.js",
metaFileName: true,
},
}),
],
});