mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 10:24:02 +00:00
- Voice layer manifest (src/voice/layerManifest.js) generates the layer enums, aliases and analyst field hints; a test fails when a catalog layer has no entry. - analyst_query validates fields, operators, units, values and scopes, counts up to 250,000 loaded records per layer, reports complete/partial/unanswered, tells LAYER_OFF / NOT_READY / FEED_UNAVAILABLE apart from zero, refuses mismatched follow-ups and never lets a superseded query replace follow-up memory. Seven more layers expose analyst records. - Tool results carry a code-built say line and a display card; the voice card in the mic control shows captions, plan steps and the result (src/voice/resultDisplay.js is the one adapter). Slow tools narrate their current step out of band; holding Space while the assistant talks cuts it off. Turn spans go to the debug log; caption transcription is metered; the log omits what was said unless GEV_VOICE_LOG_CONTENT=1. - Point and ask: the Space-down pointer snapshot resolves "this", "that one" and "around here" through 'pointer' targets, and "the second one" through referent:n from the last numbered list. - Prompt states each policy once (instructions + tools 48.5k -> 46.7k chars). - Voice benchmark harness (scripts/qa-voice-bench.mjs, scripts/voice-bench/) shares its phrase table and grading with scripts/qa-voice-routing.mjs.
96 lines
5.3 KiB
JavaScript
96 lines
5.3 KiB
JavaScript
/** 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>
|
||
<section id="gev-voice-card" class="gev-voice-card" hidden aria-label="Voice assistant">
|
||
<div class="gev-voice-card-header">
|
||
<span class="gev-voice-card-kicker">VOICE</span>
|
||
<span id="gev-voice-card-phase" class="gev-voice-card-phase"></span>
|
||
<button id="gev-voice-card-dismiss" class="gev-voice-card-dismiss" type="button" aria-label="Dismiss voice card">×</button>
|
||
</div>
|
||
<p id="gev-voice-card-user" class="gev-voice-card-caption" data-role="user" hidden><span class="gev-voice-card-who">YOU</span><span id="gev-voice-card-user-text" class="gev-voice-card-text"></span></p>
|
||
<p id="gev-voice-card-pointer" class="gev-voice-card-pointer" hidden><span id="gev-voice-card-pointer-kind" class="gev-voice-card-who">THIS</span><span class="gev-voice-card-sr">: </span><span id="gev-voice-card-pointer-text" class="gev-voice-card-pointer-label"></span></p>
|
||
<p id="gev-voice-card-assistant" class="gev-voice-card-caption" data-role="assistant" hidden><span class="gev-voice-card-who">GEV</span><span id="gev-voice-card-assistant-text" class="gev-voice-card-text"></span></p>
|
||
<ol id="gev-voice-card-plan" class="gev-voice-card-plan" aria-label="Plan" hidden></ol>
|
||
<div id="gev-voice-card-result" class="gev-voice-card-result" hidden>
|
||
<div id="gev-voice-card-result-title" class="gev-voice-card-result-title"></div>
|
||
<div id="gev-voice-card-chips" class="gev-voice-card-chips" hidden></div>
|
||
<ul id="gev-voice-card-lines" class="gev-voice-card-lines"></ul>
|
||
<ol id="gev-voice-card-referents" class="gev-voice-card-referents" aria-label="Referenced items" hidden></ol>
|
||
<details id="gev-voice-card-notes" class="gev-voice-card-notes" hidden>
|
||
<summary>NOTES & SOURCES</summary>
|
||
<ul id="gev-voice-card-note-list" class="gev-voice-card-lines"></ul>
|
||
</details>
|
||
</div>
|
||
<div id="gev-voice-card-live" class="gev-voice-card-sr" aria-live="polite" aria-atomic="true"></div>
|
||
</section>
|
||
<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'),
|
||
card: root.querySelector('#gev-voice-card'),
|
||
};
|
||
}
|