Update gpt/index.html

This commit is contained in:
2026-05-14 13:47:01 +02:00
parent b50e310e40
commit 5c8455930f
+134 -1
View File
@@ -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();