feat(settings): add end-to-end ASR provider validation#251
Conversation
Issue Open-Less#242 asks ASR to reach parity with LLM availability checks. Validation now requires a configured ASR model and verifies it exists in the provider model list, instead of only checking endpoint/auth reachability. Constraint: Keep existing settings flow and IPC shape with minimal UI change Rejected: Add a new ASR test-audio transcription request | adds latency and provider-specific request complexity Confidence: high Scope-risk: narrow Directive: Keep validate and fetch-models semantics aligned; validate should fail when configured model cannot actually be selected Tested: npm run build; cargo check -q Not-tested: Manual Settings UI interaction against live third-party ASR endpoints
ASR validation now runs one end-to-end /audio/transcriptions request with the currently selected model and a tiny bundled silence WAV payload. This verifies endpoint, auth, model routing, and response schema in one pass instead of model-list reachability only. Constraint: Keep UI/API contract unchanged and avoid touching recording pipeline Rejected: Reuse live microphone capture in settings validation | invasive and non-deterministic for quick checks Confidence: high Scope-risk: narrow Directive: Preserve providerHttpStatus:* error marker so frontend can keep status-specific guidance Tested: npm run build; cargo check -q Not-tested: Live validation against every third-party ASR provider implementation
Follow-up fixes from dual review keep the new end-to-end ASR check while removing compatibility and robustness regressions: normalize transcription endpoint URL, enforce HTTPS except localhost, cap response size, and switch to stable backend error codes mapped in i18n. Constraint: Preserve issue Open-Less#242 full-chain validation behavior with minimal surface change Rejected: Revert to model-list-only validation | no longer verifies real transcription route Confidence: high Scope-risk: narrow Directive: Keep providerHttpStatus:* and stable error-code contract synchronized with Settings error mapping Tested: npm run build; cargo check -q Not-tested: Manual validation against all third-party ASR endpoints
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 73dbd4cef7
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if trimmed.ends_with("/audio/transcriptions") { | ||
| return Ok(trimmed.to_string()); | ||
| } | ||
| Ok(format!("{trimmed}/audio/transcriptions")) |
There was a problem hiding this comment.
Normalize ASR base URLs before appending transcription path
asr_transcriptions_url only preserves URLs that already end with /audio/transcriptions; otherwise it blindly appends that suffix. This breaks validation for endpoint formats the app already accepts elsewhere (for example /chat/completions or /models, which models_url normalizes), producing invalid paths like .../chat/completions/audio/transcriptions and causing false validation failures for otherwise working provider configs.
Useful? React with 👍 / 👎.
PR Reviewer Guide 🔍(Review updated until commit cb2eb8e)Here are some key observations to aid the review process:
|
Some OpenAI-compatible deployments expose ASR under a base URL that already ends with /audio. ASR validation now treats that as a valid prefix and appends only /transcriptions to avoid generating /audio/audio/transcriptions. Constraint: Keep ASR validation URL normalization conservative and backwards-compatible Rejected: Full URL path rewrite heuristics | risk of breaking custom reverse-proxy layouts Confidence: high Scope-risk: narrow Tested: cargo test -q
|
已按 review 建议修复:asr_transcriptions_url 现在支持 base 以 /audio 结尾的配置,避免生成 /audio/audio/transcriptions,并补了对应单测。commit: fd60f81 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fd60f815c0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if trimmed.ends_with("/audio/transcriptions") { | ||
| return Ok(trimmed.to_string()); | ||
| } | ||
| if trimmed.ends_with("/audio") { | ||
| return Ok(format!("{trimmed}/transcriptions")); |
There was a problem hiding this comment.
Align ASR endpoint normalization with runtime request path
asr_transcriptions_url now treats endpoints that already end in /audio or /audio/transcriptions as valid for connection checks, but the production transcription path still appends "/audio/transcriptions" unconditionally in src-tauri/src/asr/whisper.rs (format!("{}/audio/transcriptions", base_url)). That means validation can succeed for values like https://host/v1/audio/transcriptions while real dictation later calls .../audio/transcriptions/audio/transcriptions and fails, producing a false-positive health check for users.
Useful? React with 👍 / 👎.
| if (message === 'providerResponseTooLarge') return t('settings.providers.responseTooLarge'); | ||
| if (message === 'asrInvalidJson') return t('settings.providers.asrInvalidJson'); | ||
| if (message === 'asrMissingTextField') return t('settings.providers.asrMissingTextField'); | ||
| if (message === 'providerNetworkError') return t('common.networkError'); |
There was a problem hiding this comment.
Define translation for mapped network validation error
providerErrorMessage maps providerNetworkError to t('common.networkError'), but neither en.ts nor zh-CN.ts defines common.networkError. When ASR validation hits a network failure, the UI will show a raw missing-key string instead of a user-friendly message, so the new error-code mapping degrades the settings UX in a common failure path.
Useful? React with 👍 / 👎.
|
Persistent review updated to latest commit fd60f81 |
Addresses review feedback: ASR validation now recognizes OpenAI-style /chat/completions endpoints when building the /audio/transcriptions URL, and response-size protection is enforced while streaming the body instead of after buffering it all. Constraint: Keep ASR validation behavior provider-agnostic and minimal in scope Rejected: Heuristic URL rewrites beyond known suffixes | risk of breaking custom reverse proxies Confidence: high Scope-risk: narrow Directive: If changing reqwest features, keep Cargo.lock in sync and re-run tests Tested: cargo test -q
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
已处理 reviewer guide 的两点:
|
|
Persistent review updated to latest commit df2d51e |
ASR validation URL normalization now edits the parsed URL path instead of string-appending to the raw endpoint, so endpoints with query parameters (e.g. api-version) remain valid after adding /audio/transcriptions. Constraint: Keep endpoint normalization minimal and avoid changing query/fragment semantics Rejected: Drop query parameters during validation | would break Azure-style OpenAI-compatible deployments Confidence: high Scope-risk: narrow Tested: cargo test -q
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
已修复 URL Parsing:asr_transcriptions_url 现在基于 Url 解析后仅修改 path(保留 query/fragment),避免带 query 的 endpoint 被拼坏;并补了 query 参数的单测。commit: cb2eb8e |
|
Persistent review updated to latest commit cb2eb8e |
User description
Summary
/audio/transcriptionschain check with the selected modelValidation
Closes #242
PR Type
Enhancement, Tests
Description
Add end‑to‑end ASR connection check via
/audio/transcriptionswith a silence WAVHarden validation: URL normalisation, HTTPS enforcement (localhost excluded), response‑size cap
Map new ASR validation error codes to i18n strings in Settings UI
Add unit tests for
asr_transcriptions_urland enablereqweststream featureDiagram Walkthrough
File Walkthrough
commands.rs
Add end‑to‑end ASR validation via transcription endpointopenless-all/app/src-tauri/src/commands.rs
validate_asr_providerthatperforms a real transcription call
validate_asr_transcription: sends a 250 ms silence WAV,checks HTTP status, enforces a 1 MB response cap, and verifies the
JSON
textfieldasr_transcriptions_urlto normalise base URL paths and enforceHTTPS (except localhost)
encode_wav_16k_mono_silencehelper to create the test audiopayload
asr_transcriptions_urlcovering different inputURL patterns
en.ts
Add English i18n for ASR validation errorsopenless-all/app/src/i18n/en.ts
(endpoint HTTPS requirement, invalid JSON, missing text field,
response too large)
zh-CN.ts
Add Chinese i18n for ASR validation errorsopenless-all/app/src/i18n/zh-CN.ts
Settings.tsx
Map new ASR validation errors to Settings UI messagesopenless-all/app/src/pages/Settings.tsx
asrModelMissingthe same asllmModelMissingduring validationmodelsEmptyerror uniformly for both LLM and ASR providersproviderErrorMessageto map the new stable backend error codesto i18n keys
Cargo.toml
Enable reqwest stream feature for ASR response readingopenless-all/app/src-tauri/Cargo.toml
streamfeature toreqwestdependency for streaming response bodyduring ASR validation