Add OpenAI TTS support to replace system text-to-speech with high-quality AI voices#879
Add OpenAI TTS support to replace system text-to-speech with high-quality AI voices#879
Conversation
… support Co-authored-by: PeterDaveHello <3691490+PeterDaveHello@users.noreply.github.com>
There was a problem hiding this comment.
Pull Request Overview
This PR integrates OpenAI's Text-to-Speech (TTS) API to replace system-generated speech with high-quality AI voices while maintaining backward compatibility.
- Adds comprehensive OpenAI TTS service with support for 6 voices, 2 models, and adjustable speed
- Implements new TTS configuration panel in extension settings
- Enhances ReadButton component with intelligent TTS selection and fallback capabilities
- Adds "Read Selected Text" context menu option for web page text selection
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
src/services/openai-tts.mjs |
New TTS service module with API integration and audio management |
src/popup/sections/GeneralPart.jsx |
Added TTS configuration UI with voice, model, and speed settings |
src/content-script/menu-tools/index.mjs |
Added context menu option for reading selected text |
src/config/index.mjs |
Added default configuration values for TTS settings |
src/components/ReadButton/index.jsx |
Enhanced with OpenAI TTS support and fallback logic |
src/_locales/zh-hans/main.json |
Chinese translations for TTS interface |
src/_locales/en/main.json |
English translations for TTS interface |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| <option value="nova" selected={config.openAiTtsVoice === 'nova'}> | ||
| Nova | ||
| </option> | ||
| <option value="shimmer" selected={config.openAiTtsVoice === 'shimmer'}> |
There was a problem hiding this comment.
Use the value prop instead of selected attribute for React select elements. The selected attribute is deprecated in React. Set the value prop on the select element to config.openAiTtsVoice || 'alloy'.
| <option value="shimmer" selected={config.openAiTtsVoice === 'shimmer'}> | |
| value={config.openAiTtsVoice || 'alloy'} | |
| onChange={(e) => { | |
| const voice = e.target.value | |
| updateConfig({ openAiTtsVoice: voice }) | |
| }} | |
| > | |
| <option value="alloy"> | |
| Alloy | |
| </option> | |
| <option value="echo"> | |
| Echo | |
| </option> | |
| <option value="fable"> | |
| Fable | |
| </option> | |
| <option value="onyx"> | |
| Onyx | |
| </option> | |
| <option value="nova"> | |
| Nova | |
| </option> | |
| <option value="shimmer"> |
| <option value="tts-1" selected={config.openAiTtsModel === 'tts-1'}> | ||
| TTS-1 (Standard) | ||
| </option> | ||
| <option value="tts-1-hd" selected={config.openAiTtsModel === 'tts-1-hd'}> |
There was a problem hiding this comment.
Use the value prop instead of selected attribute for React select elements. The selected attribute is deprecated in React. Set the value prop on the select element to config.openAiTtsModel || 'tts-1'.
| <option value="tts-1-hd" selected={config.openAiTtsModel === 'tts-1-hd'}> | |
| value={config.openAiTtsModel || 'tts-1'} | |
| onChange={(e) => { | |
| const model = e.target.value | |
| updateConfig({ openAiTtsModel: model }) | |
| }} | |
| > | |
| <option value="tts-1"> | |
| TTS-1 (Standard) | |
| </option> | |
| <option value="tts-1-hd"> |
| {config.enableOpenAiTts && ( | ||
| <> | ||
| <label> | ||
| <legend>{t('TTS Voice')}</legend> |
There was a problem hiding this comment.
The legend element should not be used inside a label. Use a span or div element instead, or move the legend outside the label if you need fieldset grouping.
| <legend>{t('TTS Voice')}</legend> | |
| <span>{t('TTS Voice')}</span> |
| </select> | ||
| </label> | ||
| <label> | ||
| <legend>{t('TTS Model')}</legend> |
There was a problem hiding this comment.
The legend element should not be used inside a label. Use a span or div element instead, or move the legend outside the label if you need fieldset grouping.
| <legend>{t('TTS Model')}</legend> | |
| <span>{t('TTS Model')}</span> |
| </select> | ||
| </label> | ||
| <label> | ||
| <legend>{t('TTS Speed')}</legend> |
There was a problem hiding this comment.
The legend element should not be used inside a label. Use a span or div element instead, or move the legend outside the label if you need fieldset grouping.
| <legend>{t('TTS Speed')}</legend> | |
| <span>{t('TTS Speed')}</span> |
This PR implements OpenAI Text-to-Speech (TTS) functionality to address the issue of robotic and unnatural system voice synthesis. The implementation provides users with high-quality AI-generated voices while maintaining full backward compatibility.
Key Features
OpenAI TTS Integration
/v1/audio/speech)Enhanced User Experience
Technical Implementation
src/services/openai-tts.mjs)Usage
The implementation automatically detects TTS availability and falls back to system speech synthesis when needed, ensuring all existing functionality continues to work seamlessly.
Internationalization
Added translations for English and Chinese (Simplified) to support the new TTS settings interface.
Fixes #787.
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.