feat: add Fish Audio as native TTS provider#1526
feat: add Fish Audio as native TTS provider#1526xuan0x0 wants to merge 14 commits intomoeru-ai:mainfrom
Conversation
- Add fish-audio provider entry with a custom fetch override that translates xsai generateSpeech requests to Fish Audio's POST /v1/tts format (text + reference_id in body) - Add Vite dev proxy (/fish-audio-api → https://api.fish.audio) to bypass browser CORS — Fish Audio's API is server-to-server only and does not send Access-Control-Allow-Origin for browser origins - Add listFishAudioVoices helper that fetches own models and top public models in parallel, merges and deduplicates them with own models first - Add fish-audio settings page with SpeechPlayground integration - Add i18n strings for all 9 supported locales - Improve TTS error logging in Stage.vue (was silently swallowing errors) Made-with: Cursor
⏳ Approval required for deploying to Cloudflare Workers (Preview) for stage-web.
Hey, maintainers, kindly take some time to review and approve this deployment when you are available. Thank you! 🙏 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 71bd789da9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
Code Review
This pull request introduces support for the Fish Audio speech provider, including a new settings page, a Vite dev server proxy to handle CORS, and the necessary store logic for text-to-speech generation and voice listing. Feedback focuses on improving the robustness of the custom fetch implementation by forwarding abort signals for better resource management and adding safer handling for body parsing to prevent potential runtime exceptions.
…voice reload - Forward init.signal to the custom Fish Audio fetch so the HTTP request is cancelled when the TTS pipeline is aborted (e.g. user interrupts playback) - Guard the Vite dev-server proxy rewrite with a userAgent Electron check; Electron's renderer has no matching proxy route so the rewrite caused 404s - Debounce the apiKey/baseUrl watcher in fish-audio.vue (800 ms) to avoid firing repeated requests with partial credentials on every keystroke Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 80427db7be
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Add /fish-audio-api proxy to apps/stage-pocket/vite.config.ts so that stage-pocket DEV builds don't 404 when providers.ts rewrites the base URL. Previously the rewrite was only guarded against Electron, causing 404s in Capacitor dev mode where no matching proxy existed. Update the NOTICE comment in providers.ts to reference both vite configs. Made-with: Cursor
Add /fish-audio-api proxy to apps/stage-pocket/vite.config.ts so that stage-pocket DEV builds don't 404 when providers.ts rewrites the base URL. Previously the rewrite was only guarded against Electron, causing 404s in Capacitor dev mode where no matching proxy existed. Update the NOTICE comment in providers.ts to reference both vite configs.
….com/xuan0x0/airi into xuanpan/feat/fish-audio-tts-provider
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c8bc7bfcc9
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
validateProviderConfig now surfaces a clear error when the default api.fish.audio URL is used in contexts where browser CORS will block the request and no proxy/IPC path exists: - Electron (all modes): renderer enforces CORS; IPC path not yet built - Web/Capacitor production: Vite dev-server proxy is absent Capacitor native builds (iOS/Android) are exempt because the OS HTTP stack is not subject to browser CORS. Users with a custom base URL (self-hosted CORS proxy) are unaffected. Adds a TODO comment marking the Electron IPC path as follow-up work. Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 540df09ba7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
…or guard `navigator.gpu` is a WebGPU-only property not present in the standard TypeScript DOM lib, causing TS2339 errors in packages whose tsconfigs do not include WebGPU types. Replace all live usages of `!!navigator.gpu` with `'gpu' in navigator` (boolean presence check, no extra lib needed), and for call sites that also invoke `navigator.gpu.requestAdapter()` use a minimal structural cast after the `in` guard confirms existence. Made-with: Cursor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50aa33ca34
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| defaultOptions: () => { | ||
| const capabilities = getCachedWebGPUCapabilities() | ||
| const hasWebGPU = capabilities?.supported ?? (typeof navigator !== 'undefined' && !!navigator.gpu) | ||
| const hasWebGPU = capabilities?.supported ?? (typeof navigator !== 'undefined' && 'gpu' in navigator) |
There was a problem hiding this comment.
Check navigator.gpu value, not just property presence
Using 'gpu' in navigator can report WebGPU as available even when navigator.gpu resolves to undefined (for example in contexts where the API is exposed but not usable), which makes Kokoro default/model-selection logic treat unsupported environments as supported and then fail later when loading WebGPU models. The previous !!navigator.gpu guard avoided this false-positive path.
Useful? React with 👍 / 👎.
| if (!config.apiKey) { | ||
| errors.push(new Error('API key is required.')) |
There was a problem hiding this comment.
Trim Fish API key during provider validation
validateProviderConfig only checks !config.apiKey, so a whitespace-only key is treated as valid, but createProvider trims the key before use and will send an empty bearer token. This marks the provider configured while all voice/TTS requests fail with auth errors; validating config.apiKey.trim() would keep configured state aligned with runtime behavior.
Useful? React with 👍 / 👎.
Closes #1477
Summary
Adds Fish Audio as a native TTS provider, alongside existing providers like OpenAI, ElevenLabs, and Kokoro.
fetchoverride translates@xsai/generate-speechrequests to Fish Audio'sPOST /v1/ttsformat (text+reference_idin the JSON body)Access-Control-Allow-Originfor browser origins. A Vite dev server proxy (/fish-audio-api → https://api.fish.audio) is added toapps/stage-web/vite.config.tsso requests appear same-origin in development. Users who deploy their own instance can point the base URL at their own reverse proxy./settings/providers/speech/fish-audiopage with API key input, base URL override, voice selector, and test playgroundStage.vuewas silently swallowing errors; now logs provider/model/voice/error on failureKnown limitations / follow-ups
modelHTTP request header, but sending custom headers from the browser triggers a CORS preflight that Fish Audio's CDN rejects. The server defaults tos2-pro, which is the only model listed. This matches the behaviour of the official Fish Audio JS SDK.stage-tamagotchi(Electron) — Electron's renderer is also subject to CORS. A separate proxy via the Electron main process is not yet implemented and is left as a follow-up.Test plan
s2-pro) and a voice