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;
                }
            });
        })();