AI responses now use main page voice selection
new file: CLAUDE.md modified: uncloseai.js
This commit is contained in:
parent
9ce4e261e0
commit
84a90f4dc2
2 changed files with 72 additions and 40 deletions
21
CLAUDE.md
Normal file
21
CLAUDE.md
Normal file
|
|
@ -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
|
||||
91
uncloseai.js
91
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);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue