mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 17:00:15 +01:00
🔊 fix(tts): NotAllowedError (mobile/safari), Unsupported MediaSource type (firefox), Hide Audio Element (#2854)
* fix: hide audio element on mobile * chore: add tts docs link * fix: select voice option on first render * fix: NotAllowedError, prevent async playback for mobile triggers, consolidate MessageAudio code, user user-triggered unmutes * fix: Firefox/unsupported type for MediaSource hack * refactor(STT): make icon red when recording. consolidate logic to AudioRecorder component * fix: revert Redis changes to use separate client for sessions
This commit is contained in:
parent
dcd2e3e62d
commit
35ba4ba1a4
14 changed files with 421 additions and 130 deletions
|
|
@ -88,7 +88,7 @@ export default function StreamAudio({ index = 0 }) {
|
|||
return;
|
||||
}
|
||||
|
||||
console.log('Fetching audio...');
|
||||
console.log('Fetching audio...', navigator.userAgent);
|
||||
const response = await fetch('/api/files/tts', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${token}` },
|
||||
|
|
@ -103,8 +103,14 @@ export default function StreamAudio({ index = 0 }) {
|
|||
}
|
||||
|
||||
const reader = response.body.getReader();
|
||||
const mediaSource = new MediaSourceAppender('audio/mpeg');
|
||||
setGlobalAudioURL(mediaSource.mediaSourceUrl);
|
||||
|
||||
const type = 'audio/mpeg';
|
||||
const browserSupportsType = MediaSource.isTypeSupported(type);
|
||||
let mediaSource: MediaSourceAppender | undefined;
|
||||
if (browserSupportsType) {
|
||||
mediaSource = new MediaSourceAppender(type);
|
||||
setGlobalAudioURL(mediaSource.mediaSourceUrl);
|
||||
}
|
||||
setAudioRunId(activeRunId);
|
||||
|
||||
let done = false;
|
||||
|
|
@ -120,7 +126,7 @@ export default function StreamAudio({ index = 0 }) {
|
|||
if (cacheTTS && value) {
|
||||
chunks.push(value);
|
||||
}
|
||||
if (value) {
|
||||
if (value && mediaSource) {
|
||||
mediaSource.addData(value);
|
||||
}
|
||||
done = readerDone;
|
||||
|
|
@ -136,8 +142,19 @@ export default function StreamAudio({ index = 0 }) {
|
|||
if (!cacheKey) {
|
||||
throw new Error('Cache key not found');
|
||||
}
|
||||
const audioBlob = new Blob(chunks, { type: 'audio/mpeg' });
|
||||
cache.put(cacheKey, new Response(audioBlob));
|
||||
const audioBlob = new Blob(chunks, { type });
|
||||
const cachedResponse = new Response(audioBlob);
|
||||
await cache.put(cacheKey, cachedResponse);
|
||||
if (!browserSupportsType) {
|
||||
const unconsumedResponse = await cache.match(cacheKey);
|
||||
if (!unconsumedResponse) {
|
||||
throw new Error('Failed to fetch audio from cache');
|
||||
}
|
||||
const audioBlob = await unconsumedResponse.blob();
|
||||
const blobUrl = URL.createObjectURL(audioBlob);
|
||||
setGlobalAudioURL(blobUrl);
|
||||
}
|
||||
setIsFetching(false);
|
||||
}
|
||||
|
||||
console.log('Audio stream reading ended');
|
||||
|
|
@ -194,9 +211,16 @@ export default function StreamAudio({ index = 0 }) {
|
|||
ref={audioRef}
|
||||
controls
|
||||
controlsList="nodownload nofullscreen noremoteplayback"
|
||||
className="absolute h-0 w-0 overflow-hidden"
|
||||
style={{
|
||||
position: 'absolute',
|
||||
overflow: 'hidden',
|
||||
display: 'none',
|
||||
height: '0px',
|
||||
width: '0px',
|
||||
}}
|
||||
src={globalAudioURL || undefined}
|
||||
id={globalAudioId}
|
||||
muted
|
||||
autoPlay
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue