New Text to Speech experiment - #888
Conversation
…udio processing so we stay under API limits
…mbines those into a single file
…t to the AI Client to generate speech. Set up to be used for both Ability calls and background jobs
… Fires individual jobs, via cron, that will chunk content down and turn those into audio files, combining all files at the end
… a string of text or post content from a specific post ID
…nd imports it into the media library as an MP3 file
…he admin to make things look better. Add a better loading state and an icon to the button
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the Unlinked AccountsThe following contributors have not linked their GitHub and WordPress.org accounts: @drzraf. Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases. If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #888 +/- ##
=============================================
+ Coverage 74.57% 74.77% +0.19%
- Complexity 3132 3355 +223
=============================================
Files 132 141 +9
Lines 12213 13224 +1011
=============================================
+ Hits 9108 9888 +780
- Misses 3105 3336 +231
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@dkotter should we work to get those two provider plugin PRs merged & into a release before pressing much further ahead on this PR? |
Yeah, not much point in releasing this here until we have at least one provider that supports it. I've bumped this to the next milestone so hopefully by then the upstream PRs are merged and released |
|
I have been workin on the Elevenlabs provider. Would love to hear how it works with this experiment. |
Thanks for pointing me at that. Tested that quickly and it currently does not work due to two issues:
Seems ElevenLabs requires you to pass in a voice ID which we don't do in this PR. We do support passing in a custom voice option though we don't surface a setting for that anywhere. I temporarily added this line to our code Will need to decide here whether we surface a setting that allows a user to choose a voice (ideally dynamically pulling in the voice options the provider supports and probably defaulting to the first in the list in case someone doesn't care to choose) or that's also a change you could make on your end, hardcoding a voice ID if one isn't passed (though I don't know enough about ElevenLabs to know if voice IDs are unique per account) |
Providers like ElevenLabs require a voice ID for text to speech and fail when none is configured. Introduce a Voice_Resolver that reads the resolved model's metadata for voices declared as supported values on the outputSpeechVoice option: - The Voice setting becomes a dynamic select when the provider declares its voices, defaulting to the first available voice at generation time when the setting is empty. Falls back to the existing free-text field when no voices are declared. - A new wpai_tts_default_voice filter lets site or provider plugins supply a default voice even when the model metadata declares none. - The raw provider exception for a missing voice is mapped to an actionable error pointing at the Voice setting. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
@dkotter Following up on the ElevenLabs voice ID discussion above: Provider side: I've released ElevenLabs provider 0.3.0 which fixes both issues you found. The TTS (and sound generation) models now declare inline Plugin side: I also took a stab at the "dynamically pull voices and default to the first one" idea and opened dkotter#5 against your |
Most TTS (for accessibility etc...) distinguish between voice and language. If you choose a voice, you generally also have a distinct language setting alongside. (Both are important to generate audio output and inferring a language from a voice or vice-versa may not be obvious) To take one example, the speechd Speech Synthesis Interface Protocol considers:
(not to mention the speed, which is different from the playback speed) |
|
I would also suggest one missing feature: the ability to easily filter by post-type (or just pass the post to allow for more granular control [sticky/date/...]). The vast majority of websites would likely want to selectively use it based on specific post type. |
…ice no longer exists
…o it's used for each chunk
Add voice resolution and defaulting to the Text to Speech experiment
Thanks @saarnilauri! Made a few changes but looked good so I've merged that in now |
@drzraf I don't believe OpenAI supports passing in a language (or even Google), they just infer the language from the text you send. ElevenLabs does allow you to pass the language code but it also will default to using the language of the text you send. I guess I see no reason to complicate this further and introduce a setting to set the language when we can just rely on the LLM to match the language of the content given.
I guess not sure what the request is here? Right now you have to manually trigger TTS, so you as a user choose what post that is run on. Is the thought here to provide a way for a user to limit the output of that generate button? |
…e want. This value is passed through a filter so we can't blindly trust it but PHPStan was complaining about the old approach
Assume the LLM fails the language detection for my post. What would be the steps to follow to overcome this (or would I be stuck, unable to associate a spoken version of the post?) |
If this happens then yes, the audio generated wouldn't be what you want (or if the LLM errors instead, you wouldn't have any audio). This feels fairly unlikely to me that an LLM supports your language but can't generate speech without you telling it the language but I guess that may happen. Curious if this is a scenario you've run into before? I personally still lean towards not complicating the UI by adding an additional setting a user has to consider and just assuming/hoping each AI service can detect the language properly. If we get actual user reports that run into problems with that, we can then look to add this in, though will need to figure out how to allow someone to set a language but not have that break integrations (like OpenAI) that don't support passing in a language. |
|
I'm completely with you about not complicating the UI. What I'm a bit worried about is the limited internal API/hooks. Because if UI/network/LLM/service/quota/payment fails, that's what one would use ( There are many ways language could be badly interpreted. For example, in STT (whisper), the understanding is language-neutral (because of the way training is done for natively mulilingual dataset/STT). Language acts as a "hint" but also condition the text output language. English with language=french would output the English transcribed text translated in French. Non-English users may also have posts containing English expressions mixed up with their native language and I'm not sure these are situation where auto-detection is 100% reliable. Basically, if install my local WordPress instance + AI endpoint + Making language selection at the hook/filter level + audio attachment decoupled from LLM generation itself may make the whole workflow more resilient for unexpected cases. For a component relying so much on network/3rd-party service/non-deterministic process, it may be desirable. |
Note
This is dependent on changes coming to the OpenAI Provider (see PR 42) or Google Provider (see PR 31)
What?
Adds a new experiment, Text to Speech, that allows editors the ability to on-demand generate speech for a post, including the title and post content. This is then displayed as a player on the front-end or that can be turned off on a post by post basis.
Why?
Adding support for Text to Speech allows sites to provide their users with the ability to listen to content instead of having to read the content.
How?
ai/speech-generationandai/speech-import. These can be used to generate speech from text and import that speech as an audio file into the Media LibraryUse of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Opus 4.8
Used for: Help with initial planning and implementation. Refinement, review and testing done by me
Testing Instructions
Screenshots
Changelog Entry