diff --git a/openspec/changes/openai-transcriber/design.md b/openspec/changes/openai-transcriber/design.md index 0526baa..dc52c01 100644 --- a/openspec/changes/openai-transcriber/design.md +++ b/openspec/changes/openai-transcriber/design.md @@ -32,7 +32,7 @@ Core (`src/core/`, issue #1) сохраняет запись и ведёт её |---|---| | `src/core/ports.ts` | + `HttpRequest`, `HttpResponse`, `HttpClient` | | `src/core/multipart.ts` | `buildMultipart(fields, file, boundary) → { body: ArrayBuffer, contentType }`, побайтно через `TextEncoder`/`Uint8Array` | -| `src/core/openai.ts` | `OpenAiSettings`, `DEFAULT_OPENAI`, `REQUEST_TIMEOUT_MS`, `readSettings` (trim + наложение на умолчания), `classify(status, text)`, `redact(message, apiKey)`, `OpenAiTranscriber` | +| `src/core/openai.ts` | `OpenAiSettings`, `DEFAULT_OPENAI`, `REQUEST_TIMEOUT_MS`, `readSettings` (trim всех четырёх полей + наложение на умолчания), `classify(status, text)`, `redact(message, apiKey)`, `OpenAiTranscriber` | | `src/core/naming.ts` | + `mimeFromExt(ext)` для команды проверки | | `src/obsidian/http.ts` | `HttpClient` на `requestUrl({ url, method: 'POST', headers, contentType, body, throw: false })` | | `src/obsidian/settings.ts` | `PluginSettingTab`: четыре поля, ключ — `inputEl.type = 'password'` | @@ -101,5 +101,5 @@ new OpenAiTranscriber(http: HttpClient, settings: () => OpenAiSettings, random: 8. 2026-09-27 — Успех с пустым текстом провайдер возвращает как `ok` без изменений; «нет речи» решает очередь. *Это поведение уже закреплено в `recording-lifecycle`; дублировать его в провайдере — две точки правды.* **Нет.** 9. 2026-09-27 — Настройки в `data.json` лежат под ключом `openai` (`{ "openai": {...} }`), а не плоско. *Обёртка добавит свои настройки (устройство, папки); вложенность не даст полям провайдера смешаться с ними.* **Одна лишняя вложенность, если других настроек так и не появится.** 10. 2026-09-27 — Команда «Проверить провайдер распознавания» берёт последний по имени файл `voice/source/*.{m4a,webm,ogg}` (имена начинаются с UTC-времени, последний по имени = самый свежий), mime — по расширению через новую `mimeFromExt`. Файлы `.bin` не берутся. Сама команда и её граница «только Notice, без записи в заметки и очередь» приняты человеком; выбор файла — нет. *Не нужен UI выбора файла; свежая запись — самый показательный образец.* **Если последняя запись — тишина или битый файл, проверка покажет «речь не распознана» или ошибку сервиса, хотя провайдер исправен; пользователь увидит это по тексту уведомления.** -11. 2026-09-27 — `language` тоже обрезается от пробелов (человек назвал `trim` для `apiKey` и `baseUrl`). *Строка из пробелов иначе ушла бы как значение `language` и дала бы 400.* **Нет.** +11. 2026-09-27 — `language` тоже обрезается от пробелов (человек назвал `trim` для `apiKey` и `baseUrl`). Пересмотрено: человек на ревью спеки добавил `trim` и для `model` — обрезаются все четыре настройки. *Строка из пробелов иначе ушла бы как значение поля и дала бы 400.* **Нет.** 12. 2026-09-27 — Интеграционный тест не сверяет текст дословно; таймаут теста vitest — 2 минуты. Число совпадений (≥ 4 из 5–6 слов) задано человеком. *Модель недетерминирована; 86 КБ аудио распознаются за секунды, 2 минуты — запас на медленную сеть.* **Редкий ложный провал при сильном расхождении модели.** diff --git a/openspec/changes/openai-transcriber/specs/transcription-provider/spec.md b/openspec/changes/openai-transcriber/specs/transcription-provider/spec.md index 19c2c99..ad6d8e8 100644 --- a/openspec/changes/openai-transcriber/specs/transcription-provider/spec.md +++ b/openspec/changes/openai-transcriber/specs/transcription-provider/spec.md @@ -8,7 +8,7 @@ ### Requirement: Настройки провайдера -Провайдер MUST использовать настройки `baseUrl`, `model`, `apiKey`, `language` со значениями по умолчанию `https://api.aitunnel.ru/v1`, `gpt-4o-transcribe`, пустая строка и пустая строка соответственно. Настройки MUST храниться только в `data.json` плагина и MUST читаться заново при каждом запросе, так что изменённый ключ применяется к следующему запросу без перезапуска плагина. Значения `baseUrl`, `apiKey` и `language` MUST обрезаться от пробелов при чтении. Сохранённые настройки MUST накладываться поверх значений по умолчанию, чтобы отсутствующее поле получало умолчание. API-ключ MUST NOT попадать в репозиторий: ни в исходники, ни в тесты, ни в фикстуры. +Провайдер MUST использовать настройки `baseUrl`, `model`, `apiKey`, `language` со значениями по умолчанию `https://api.aitunnel.ru/v1`, `gpt-4o-transcribe`, пустая строка и пустая строка соответственно. Настройки MUST храниться только в `data.json` плагина и MUST читаться заново при каждом запросе, так что изменённый ключ применяется к следующему запросу без перезапуска плагина. Значения `baseUrl`, `model`, `apiKey` и `language` MUST обрезаться от пробелов при чтении. Сохранённые настройки MUST накладываться поверх значений по умолчанию, чтобы отсутствующее поле получало умолчание. API-ключ MUST NOT попадать в репозиторий: ни в исходники, ни в тесты, ни в фикстуры. #### Scenario: Первый запуск - **WHEN** плагин загружается, а `data.json` отсутствует