Contact the GutWise Team
Have questions about the GutWise 8-week reset, partnerships, or media opportunities? Share a few details below and we'll respond within one business day.
const setLabel = (state) => {
if (!labelEl) {
return;
}
const defaultText = labelEl.getAttribute('data-label-default') || labelEl.textContent || 'Listen to this page';
const loadingText = labelEl.getAttribute('data-label-loading') || 'Generating audio…';
const stopText = labelEl.getAttribute('data-label-stop') || 'Stop page narration';
if (state === 'loading') {
labelEl.textContent = loadingText;
} else if (state === 'playing') {
labelEl.textContent = stopText;
} else {
labelEl.textContent = defaultText;
}
};
const updateStatus = (message) => {
if (statusEl) {
statusEl.textContent = message || '';
}
};
const resetButton = () => {
playButton.disabled = false;
playButton.setAttribute('aria-busy', 'false');
playButton.dataset.state = 'idle';
setLabel('idle');
};
const stopPlayback = (message) => {
if (currentAudio) {
currentAudio.pause();
currentAudio.currentTime = 0;
currentAudio = null;
}
if (audioUrl) {
URL.revokeObjectURL(audioUrl);
audioUrl = '';
}
resetButton();
if (message) {
updateStatus(message);
}
};
const promptForValue = (existing, dataValue, promptMessage) => {
if (existing) {
return existing;
}
if (dataValue) {
return dataValue;
}
const response = window.prompt(promptMessage);
return response ? response.trim() : '';
};
playButton.addEventListener('click', async () => {
if (isRequestPending) {
return;
}
if (currentAudio && !currentAudio.paused) {
stopPlayback('Playback stopped.');
return;
}
const pageText = (document.body && document.body.innerText) ? document.body.innerText.trim() : '';
if (!pageText) {
updateStatus('No readable text found on this page.');
return;
}
apiKey = promptForValue(apiKey, playButton.dataset.apiKey, 'Enter your ElevenLabs API key');
if (!apiKey) {
updateStatus('Playback cancelled: API key required.');
return;
}
voiceId = promptForValue(voiceId, playButton.dataset.voiceId, 'Enter the ElevenLabs voice ID to use');
if (!voiceId) {
updateStatus('Playback cancelled: voice ID required.');
return;
}
const modelId = playButton.dataset.modelId || 'eleven_multilingual_v2';
setLabel('loading');
playButton.disabled = true;
playButton.setAttribute('aria-busy', 'true');
playButton.dataset.state = 'loading';
updateStatus('Requesting audio from ElevenLabs…');
try {
isRequestPending = true;
const response = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${encodeURIComponent(voiceId)}`, {
method: 'POST',
headers: {
'xi-api-key': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify({
text: pageText,
model_id: modelId,
voice_settings: {
stability: 0.7,
similarity_boost: 0.75
}
})
});
if (!response.ok) {
let errorMessage = 'Playback failed. Check your ElevenLabs credentials.';
try {
const errorData = await response.json();
if (errorData && typeof errorData === 'object') {
const detailMessage = errorData?.detail?.message || errorData?.detail;
if (typeof detailMessage === 'string') {
errorMessage = detailMessage;
}
}
} catch (parseError) {
const rawMessage = await response.text();
if (rawMessage) {
errorMessage = rawMessage;
}
}
throw new Error(errorMessage);
}
const blob = await response.blob();
if (currentAudio) {
currentAudio.pause();
currentAudio = null;
}
if (audioUrl) {
URL.revokeObjectURL(audioUrl);
}
audioUrl = URL.createObjectURL(blob);
const audio = new Audio(audioUrl);
currentAudio = audio;
audio.addEventListener('ended', () => {
stopPlayback('Playback finished.');
});
audio.addEventListener('error', () => {
stopPlayback('Unable to play audio.');
});
playButton.disabled = false;
playButton.setAttribute('aria-busy', 'false');
playButton.dataset.state = 'playing';
setLabel('playing');
updateStatus('Playing page audio…');
try {
await audio.play();
} catch (playError) {
stopPlayback('Playback was blocked by the browser.');
}
} catch (error) {
console.error(error);
resetButton();
updateStatus(error instanceof Error ? error.message : 'Playback failed.');
} finally {
isRequestPending = false;
}
});
})();