mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-12 06:12:18 +00:00
refactor: separate voice controls and configurable Realtime connections
This commit is contained in:
1 parent
0ba00f4662
commit
1a1cbadf5b
21 files changed
+3126
-2793
No files matched your search
@@ -0,0 +1,72 @@
|
||||
/** Build the voice control independently of its connection backend. */
|
||||
export function createVoiceControl({ reset = false } = {}) {
|
||||
let root = document.getElementById('gev-voice-control');
|
||||
if (root && reset) {
|
||||
root.remove();
|
||||
root = null;
|
||||
}
|
||||
if (!root) {
|
||||
root = document.createElement('div');
|
||||
root.id = 'gev-voice-control';
|
||||
root.dataset.status = 'idle';
|
||||
root.dataset.speaker = 'idle';
|
||||
root.innerHTML = `
|
||||
<div class="gev-voice-heading">
|
||||
<div class="gev-voice-kicker">AI AGENT</div>
|
||||
<div id="gev-voice-status">OFF</div>
|
||||
<div class="gev-voice-cost">
|
||||
<button id="gev-voice-tier" class="gev-voice-tier-btn" type="button" aria-pressed="false" title="Voice model tier — applies next session">STD</button>
|
||||
<span id="gev-voice-cost-value" class="gev-voice-cost-value" data-level="ok" title="Estimated session cost">~$0.00</span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="gev-voice-button" type="button" aria-label="Voice control — activate to toggle voice; hold Space to speak" aria-describedby="gev-voice-help">
|
||||
<span class="gev-mic-orbit"><img src="/mic.svg" alt="" /></span>
|
||||
<span class="gev-mic-label">ON/OFF</span>
|
||||
</button>
|
||||
<div class="gev-voice-visualizer" aria-hidden="true">
|
||||
${Array.from({ length: 15 }, (_, index) => `<span style="--bar:${index}"></span>`).join('')}
|
||||
</div>
|
||||
<div class="gev-voice-readout">
|
||||
<div id="gev-voice-detail">VOICE STANDBY</div>
|
||||
</div>
|
||||
<div id="gev-voice-help" class="gev-voice-help-tray" role="tooltip">
|
||||
<span class="gev-voice-help-kicker">VOICE CONTROL</span>
|
||||
<span class="gev-voice-help-detail">Hold Space to speak · tap Space to activate focused controls</span>
|
||||
</div>
|
||||
<div class="gev-voice-error-tray" role="alert" aria-live="assertive">
|
||||
<div class="gev-voice-error-header">
|
||||
<span>VOICE SYSTEM ERROR</span>
|
||||
<button class="gev-voice-error-dismiss" type="button">DISMISS</button>
|
||||
</div>
|
||||
<div id="gev-voice-error-detail"></div>
|
||||
<div class="gev-voice-error-hint">Check microphone permission and network access, then try again.</div>
|
||||
</div>
|
||||
`;
|
||||
const commandDock = document.getElementById('command-dock');
|
||||
if (commandDock) {
|
||||
const locationBar = document.getElementById('location-bar');
|
||||
const controlPanel = document.getElementById('control-panel');
|
||||
commandDock.appendChild(root);
|
||||
if (locationBar) commandDock.insertBefore(locationBar, root);
|
||||
if (controlPanel) commandDock.appendChild(controlPanel);
|
||||
} else {
|
||||
document.body.appendChild(root);
|
||||
}
|
||||
root
|
||||
.querySelector('.gev-voice-error-dismiss')
|
||||
?.addEventListener('click', () => {
|
||||
root.classList.add('error-dismissed');
|
||||
});
|
||||
}
|
||||
return {
|
||||
root,
|
||||
button: root.querySelector('#gev-voice-button'),
|
||||
buttonLabel: root.querySelector('.gev-mic-label'),
|
||||
status: root.querySelector('#gev-voice-status'),
|
||||
detail: root.querySelector('#gev-voice-detail'),
|
||||
helpDetail: root.querySelector('.gev-voice-help-detail'),
|
||||
errorDetail: root.querySelector('#gev-voice-error-detail'),
|
||||
tierButton: root.querySelector('#gev-voice-tier'),
|
||||
costValue: root.querySelector('#gev-voice-cost-value'),
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user