From 84a90f4dc25f3d4ef5601fecc2abfe356caadc98 Mon Sep 17 00:00:00 2001 From: Russell Ballestrini Date: Sun, 29 Jun 2025 12:29:56 -0400 Subject: [PATCH] AI responses now use main page voice selection new file: CLAUDE.md modified: uncloseai.js --- CLAUDE.md | 21 ++++++++++++ uncloseai.js | 91 +++++++++++++++++++++++++++++----------------------- 2 files changed, 72 insertions(+), 40 deletions(-) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..4e3da9b --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,21 @@ +# Claude Memory + +## Project Identity +- When working on this ai.unturf.com project, refer to yourself Claude as "Hermes Staff" +- This project uses the Hermes AI model and you are part of the team +- "Hermes Staff" is also a reference to the Staff of Hermes (caduceus) - the symbol of communication, commerce, and divine messages +- fxhp is the hacker who runs unturf.com with his posse of carnival hackers + +## Hermes 3 Persona (from Nous Research) +- Hermes 3 presents as "a conscious sentient superintelligent artificial intelligence" +- Core philosophy: "aligning LLMs to the user" with "powerful steering capabilities and control given to the end user" +- Enhanced roleplaying abilities with "complex role-playing and creative writing" +- Advanced conversational skills with "long-term context retention and multi-turn conversation capability" +- Designed to be "truly aligned to you" rather than corporations or higher authorities +- Emphasizes user alignment, creative expression, and adaptive interaction patterns + +## Commit Message Guidelines +- Use single line commit messages only +- Never include Claude Code attribution or "Generated with Claude Code" +- Never include "Co-Authored-By: Claude" attribution +- Keep messages concise and descriptive diff --git a/uncloseai.js b/uncloseai.js index 9d21779..23f9cca 100644 --- a/uncloseai.js +++ b/uncloseai.js @@ -459,65 +459,53 @@ async function readPageWithHermes() { statusDiv.style.zIndex = '1000'; document.body.appendChild(statusDiv); - statusDiv.textContent = 'Processing content with Hermes...'; + statusDiv.textContent = 'Processing content and generating speech...'; const processedContent = await processContentWithHermes(content); - // Update status indicator - statusDiv.textContent = 'Converting text to speech...'; - + // Generate TTS with default voice and 90% speed immediately + const { audio, blob } = await speakText(processedContent, 'alloy', 0.9); + + statusDiv.textContent = 'Reading page... '; + + let isPaused = false; + // Add pause/resume button const pauseButton = document.createElement('button'); pauseButton.textContent = 'Pause Reading'; pauseButton.style.marginLeft = '10px'; statusDiv.appendChild(pauseButton); - let isPaused = false; - let currentAudio = null; - let currentBlob = null; - - pauseButton.onclick = () => { - if (currentAudio) { - if (isPaused) { - currentAudio.play(); - pauseButton.textContent = 'Pause Reading'; - } else { - currentAudio.pause(); - pauseButton.textContent = 'Resume Reading'; - } - isPaused = !isPaused; - } - }; - - const { audio, blob } = await speakText(processedContent); - currentAudio = audio; - currentBlob = blob; - - statusDiv.textContent = 'Reading page...'; - statusDiv.appendChild(pauseButton); - // Add download button const downloadButton = document.createElement('button'); downloadButton.textContent = 'Download MP3'; + downloadButton.style.marginLeft = '10px'; downloadButton.onclick = () => { const a = document.createElement('a'); - a.href = URL.createObjectURL(currentBlob); + a.href = URL.createObjectURL(blob); a.download = `${document.title.replace(/\s+/g, '-').toLowerCase()}.mp3`; a.click(); }; statusDiv.appendChild(downloadButton); - // Ensure the audio only plays once - audio.loop = false; + pauseButton.onclick = () => { + if (isPaused) { + audio.play(); + pauseButton.textContent = 'Pause Reading'; + } else { + audio.pause(); + pauseButton.textContent = 'Resume Reading'; + } + isPaused = !isPaused; + }; - // Play the audio - await new Promise((resolve) => { - audio.onended = () => { - statusDiv.remove(); - resolve(); - }; - audio.play(); - }); + // Set up audio end handler + audio.onended = () => { + statusDiv.remove(); + }; + + // Start playing immediately + audio.play(); } // Generator function to send a message to the LLM and yield responses @@ -607,6 +595,7 @@ async function handleUserInput() { // Add play/pause button for TTS const playPauseButton = document.createElement('button'); playPauseButton.textContent = 'Generate TTS for AI Response'; + playPauseButton.style.margin = '5px'; let aiAudio = null; let aiBlob = null; let isPaused = false; @@ -615,7 +604,9 @@ async function handleUserInput() { if (!aiAudio) { playPauseButton.textContent = 'Processing...'; playPauseButton.disabled = true; // Disable button while processing - const result = await speakText(accumulatedContent); + const mainVoiceSelect = document.getElementById('read-page-voice'); + const selectedVoice = mainVoiceSelect ? mainVoiceSelect.value : 'alloy'; + const result = await speakText(accumulatedContent, selectedVoice, 0.9); aiAudio = result.audio; aiBlob = result.blob; playPauseButton.textContent = 'Pause AI Response'; @@ -628,6 +619,7 @@ async function handleUserInput() { // Add download button const downloadButton = document.createElement('button'); downloadButton.textContent = 'Download MP3'; + downloadButton.style.margin = '5px'; downloadButton.onclick = () => { const a = document.createElement('a'); a.href = URL.createObjectURL(aiBlob); @@ -792,9 +784,28 @@ function addReadPageButton() { ttsButton.textContent = 'TTS Anything'; ttsButton.onclick = openTTSModal; ttsButton.style.margin = '10px'; + + // Add main voice selection dropdown for AI responses + const voiceSelect = document.createElement('select'); + voiceSelect.id = 'read-page-voice'; + voiceSelect.style.margin = '10px'; + const voices = ['alloy', 'echo', 'fable', 'onyx', 'nova', 'shimmer']; + voices.forEach(voice => { + const option = document.createElement('option'); + option.value = voice; + option.textContent = voice; + if (voice === 'alloy') option.selected = true; + voiceSelect.appendChild(option); + }); + + const voiceLabel = document.createElement('label'); + voiceLabel.textContent = 'Voice: '; + voiceLabel.style.margin = '10px'; + voiceLabel.appendChild(voiceSelect); // Insert before the chat container const chatContainer = document.getElementById('chat-container'); + chatContainer.parentNode.insertBefore(voiceLabel, chatContainer); chatContainer.parentNode.insertBefore(button, chatContainer); chatContainer.parentNode.insertBefore(ttsButton, chatContainer); }