Update gpt/index.html
This commit is contained in:
+134
-1
@@ -589,6 +589,7 @@
|
||||
<button class="modal-tab" data-section="system">SYSTEM PROMPT</button>
|
||||
<button class="modal-tab" data-section="interface">INTERFACE</button>
|
||||
<button class="modal-tab" data-section="macros">MACROS</button>
|
||||
<button class="modal-tab" data-section="voice">VOICE</button>
|
||||
</div>
|
||||
|
||||
<!-- CONNECTION -->
|
||||
@@ -744,6 +745,50 @@ Date|What is today's date?"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- VOICE -->
|
||||
<div class="modal-section" id="section-voice">
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">ENABLE VOICE READOUT</span>
|
||||
<label class="toggle"><input type="checkbox" id="ttsToggle"><span class="toggle-slider"></span></label>
|
||||
</div>
|
||||
<div class="toggle-row">
|
||||
<span class="toggle-label">READ USER MESSAGES TOO</span>
|
||||
<label class="toggle"><input type="checkbox" id="ttsUserToggle"><span class="toggle-slider"></span></label>
|
||||
</div>
|
||||
<div class="cfg-group" style="margin-top:8px">
|
||||
<label>VOICE</label>
|
||||
<select id="ttsVoiceSelect"><option value="">-- Loading voices... --</option></select>
|
||||
</div>
|
||||
<div class="cfg-group">
|
||||
<label>RATE (speed)</label>
|
||||
<div class="range-row">
|
||||
<input type="range" id="ttsRateRange" min="0.5" max="2.5" step="0.05" value="1">
|
||||
<span class="range-val" id="ttsRateVal">1.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cfg-group">
|
||||
<label>PITCH</label>
|
||||
<div class="range-row">
|
||||
<input type="range" id="ttsPitchRange" min="0" max="2" step="0.05" value="1">
|
||||
<span class="range-val" id="ttsPitchVal">1.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="cfg-group">
|
||||
<label>VOLUME</label>
|
||||
<div class="range-row">
|
||||
<input type="range" id="ttsVolRange" min="0" max="1" step="0.05" value="1">
|
||||
<span class="range-val" id="ttsVolVal">1.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display:flex;gap:8px;margin-top:10px">
|
||||
<button class="cfg-btn" onclick="ttsTest()">▶ TEST VOICE</button>
|
||||
<button class="cfg-btn" onclick="ttsStop()">■ STOP</button>
|
||||
</div>
|
||||
<div style="font-size:11px;color:var(--t-fg-dim);margin-top:8px" id="ttsStatus">
|
||||
Web Speech API — voices depend on your browser & OS.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cfg-buttons">
|
||||
<button class="cfg-btn danger" onclick="resetConfig()">RESET</button>
|
||||
<button class="cfg-btn" onclick="closeConfig()">CANCEL</button>
|
||||
@@ -780,6 +825,12 @@ const DEFAULT_CONFIG = {
|
||||
macroBar: true,
|
||||
macros: 'Hello|Hello! Who are you?\nHelp|What can you help me with?\nDate|What is today\'s date?',
|
||||
enabled: false,
|
||||
tts: false,
|
||||
ttsUser: false,
|
||||
ttsVoice: '',
|
||||
ttsRate: 1.0,
|
||||
ttsPitch: 1.0,
|
||||
ttsVol: 1.0,
|
||||
};
|
||||
|
||||
let cfg = { ...DEFAULT_CONFIG };
|
||||
@@ -817,8 +868,90 @@ const sidebar = document.getElementById('sidebar');
|
||||
const debugPre = document.getElementById('debugPre');
|
||||
|
||||
/* ══════════════════════════════════════════
|
||||
INIT APPLY
|
||||
TTS ENGINE
|
||||
══════════════════════════════════════════ */
|
||||
let ttsVoices = [];
|
||||
let ttsSpeaking = false;
|
||||
|
||||
function ttsLoadVoices() {
|
||||
ttsVoices = speechSynthesis.getVoices();
|
||||
const sel = document.getElementById('ttsVoiceSelect');
|
||||
if (!sel) return;
|
||||
sel.innerHTML = '<option value="">System default</option>';
|
||||
ttsVoices.forEach((v, i) => {
|
||||
const opt = document.createElement('option');
|
||||
opt.value = v.name;
|
||||
opt.textContent = `${v.name} (${v.lang})`;
|
||||
if (cfg.ttsVoice && v.name === cfg.ttsVoice) opt.selected = true;
|
||||
sel.appendChild(opt);
|
||||
});
|
||||
}
|
||||
|
||||
if ('speechSynthesis' in window) {
|
||||
speechSynthesis.onvoiceschanged = ttsLoadVoices;
|
||||
ttsLoadVoices();
|
||||
} else {
|
||||
console.warn('Web Speech API not supported.');
|
||||
}
|
||||
|
||||
function ttsSpeak(text, isUser = false) {
|
||||
if (!cfg.tts) return;
|
||||
if (isUser && !cfg.ttsUser) return;
|
||||
if (!('speechSynthesis' in window)) return;
|
||||
|
||||
// Strip markdown-ish symbols so they don't get read aloud
|
||||
const clean = text
|
||||
.replace(/```[\s\S]*?```/g, 'code block')
|
||||
.replace(/`[^`]+`/g, 'code')
|
||||
.replace(/[*_#>\[\]]/g, '')
|
||||
.replace(/https?:\/\/\S+/g, 'link')
|
||||
.trim();
|
||||
if (!clean) return;
|
||||
|
||||
const utt = new SpeechSynthesisUtterance(clean);
|
||||
const voice = ttsVoices.find(v => v.name === cfg.ttsVoice);
|
||||
if (voice) utt.voice = voice;
|
||||
utt.rate = cfg.ttsRate;
|
||||
utt.pitch = cfg.ttsPitch;
|
||||
utt.volume = cfg.ttsVol;
|
||||
|
||||
utt.onstart = () => { ttsSpeaking = true; updateTtsIndicator(true); };
|
||||
utt.onend = () => { ttsSpeaking = false; updateTtsIndicator(false); };
|
||||
utt.onerror = () => { ttsSpeaking = false; updateTtsIndicator(false); };
|
||||
|
||||
speechSynthesis.cancel(); // stop any ongoing
|
||||
speechSynthesis.speak(utt);
|
||||
}
|
||||
|
||||
function ttsStop() {
|
||||
if ('speechSynthesis' in window) speechSynthesis.cancel();
|
||||
ttsSpeaking = false;
|
||||
updateTtsIndicator(false);
|
||||
}
|
||||
|
||||
function ttsTest() {
|
||||
// Re-read config values from sliders directly so test is live
|
||||
const rate = parseFloat(document.getElementById('ttsRateRange')?.value ?? cfg.ttsRate);
|
||||
const pitch = parseFloat(document.getElementById('ttsPitchRange')?.value ?? cfg.ttsPitch);
|
||||
const vol = parseFloat(document.getElementById('ttsVolRange')?.value ?? cfg.ttsVol);
|
||||
const voice = document.getElementById('ttsVoiceSelect')?.value ?? cfg.ttsVoice;
|
||||
|
||||
const utt = new SpeechSynthesisUtterance('Neural Net Terminal online. Voice readout active. All systems nominal.');
|
||||
const v = ttsVoices.find(v => v.name === voice);
|
||||
if (v) utt.voice = v;
|
||||
utt.rate = rate; utt.pitch = pitch; utt.volume = vol;
|
||||
speechSynthesis.cancel();
|
||||
speechSynthesis.speak(utt);
|
||||
}
|
||||
|
||||
function updateTtsIndicator(active) {
|
||||
const el = document.getElementById('ttsIndicator');
|
||||
if (!el) return;
|
||||
el.style.opacity = active ? '1' : '0.3';
|
||||
el.style.animation = active ? 'pulse 1s ease-in-out infinite' : 'none';
|
||||
}
|
||||
|
||||
|
||||
applyTheme();
|
||||
applyInterface();
|
||||
updateStatus();
|
||||
|
||||
Reference in New Issue
Block a user