Upgrade to rom-control v2 Client API; rename app.js → commander.js; hide incomplete telepresence/animator pages
This commit is contained in:
@@ -81,7 +81,8 @@
|
||||
<div style="display:flex;align-items:center;gap:6px;margin-bottom:8px;">
|
||||
<input type="checkbox" id="llm-toggle" style="width:auto;">
|
||||
<label for="llm-toggle" style="margin:0;cursor:pointer;">LLM voice loop</label>
|
||||
<button id="btn-llm-clear" style="margin-left:auto;font-size:11px;padding:2px 8px;" title="Clear conversation history">↺ Clear</button>
|
||||
<button id="btn-llm-cancel" class="danger" style="margin-left:auto;font-size:11px;padding:2px 8px;" title="Cancel active LLM request">✕ Stop</button>
|
||||
<button id="btn-llm-clear" style="font-size:11px;padding:2px 8px;" title="Clear conversation history">↺ Clear</button>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>Completions endpoint</label>
|
||||
@@ -281,6 +282,6 @@
|
||||
<img id="photo-modal-img" src="" alt="Photo">
|
||||
</div>
|
||||
|
||||
<script src="app.js"></script>
|
||||
<script src="commander.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -59,7 +59,8 @@ function handleJiboEvent(body, txId) {
|
||||
switch (body.Event) {
|
||||
case 'onHotWordHeard':
|
||||
flashHotword(body.utterance || 'hey jibo', body.score);
|
||||
if (document.getElementById('auto-listen-toggle').checked) doListen();
|
||||
if (document.getElementById('auto-listen-toggle').checked)
|
||||
post('/api/interrupt').then(() => doListen());
|
||||
break;
|
||||
|
||||
case 'onStart':
|
||||
@@ -257,7 +258,7 @@ document.getElementById('btn-say').addEventListener('click', async () => {
|
||||
});
|
||||
|
||||
document.getElementById('btn-say-cancel').addEventListener('click', () => {
|
||||
if (lastSayTx) post('/api/cancel', { txId: lastSayTx });
|
||||
post('/api/say/cancel');
|
||||
});
|
||||
|
||||
// ── Listen ────────────────────────────────────────────────────────────────────
|
||||
@@ -288,20 +289,28 @@ document.getElementById('btn-listen').addEventListener('click', doListen);
|
||||
|
||||
document.getElementById('btn-listen-cancel').addEventListener('click', () => {
|
||||
clearListenTimeout();
|
||||
if (lastListenTx) post('/api/cancel', { txId: lastListenTx });
|
||||
post('/api/listen/cancel');
|
||||
document.getElementById('listen-result').textContent = '(cancelled)';
|
||||
});
|
||||
|
||||
// ── Auto-listen + Voice AI ────────────────────────────────────────────────────
|
||||
|
||||
let llmHistory = []; // [{role:'user'|'assistant', content:string}]
|
||||
let llmHistory = []; // [{role:'user'|'assistant', content:string}]
|
||||
let llmSessionMode = false; // true when server uses LLM_SESSION_KEY (OpenClaw session)
|
||||
let llmTurnCount = 0;
|
||||
|
||||
function llmStatus(msg) {
|
||||
document.getElementById('llm-status').textContent = msg;
|
||||
}
|
||||
|
||||
async function runLLMLoop(speechText) {
|
||||
llmHistory.push({ role: 'user', content: speechText });
|
||||
// In session mode send only the latest message — history lives on the server.
|
||||
// In history mode accumulate the full thread and send it each time.
|
||||
const messages = llmSessionMode
|
||||
? [{ role: 'user', content: speechText }]
|
||||
: [...llmHistory, { role: 'user', content: speechText }];
|
||||
|
||||
if (!llmSessionMode) llmHistory.push({ role: 'user', content: speechText });
|
||||
llmStatus('Thinking…');
|
||||
|
||||
const endpoint = document.getElementById('llm-endpoint').value.trim();
|
||||
@@ -309,30 +318,45 @@ async function runLLMLoop(speechText) {
|
||||
const systemPrompt = document.getElementById('llm-system-prompt').value.trim();
|
||||
|
||||
const r = await post('/api/llm/chat', {
|
||||
messages: llmHistory,
|
||||
messages,
|
||||
endpoint: endpoint || undefined,
|
||||
model: model || undefined,
|
||||
systemPrompt: systemPrompt || undefined,
|
||||
});
|
||||
|
||||
if (!r || r.error) {
|
||||
if (r?.error === 'cancelled') { llmStatus('Interrupted.'); if (!llmSessionMode) llmHistory.pop(); return; }
|
||||
llmStatus('LLM error: ' + (r?.error || 'no response'));
|
||||
llmHistory.pop(); // undo the user push so history stays consistent
|
||||
if (!llmSessionMode) llmHistory.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
const reply = r.reply;
|
||||
llmHistory.push({ role: 'assistant', content: reply });
|
||||
llmStatus(`[${llmHistory.length / 2} turns] Last: "${reply.slice(0, 60)}${reply.length > 60 ? '…' : ''}"`);
|
||||
if (!llmSessionMode) llmHistory.push({ role: 'assistant', content: reply });
|
||||
llmTurnCount++;
|
||||
const modeTag = llmSessionMode ? 'session' : 'local';
|
||||
llmStatus(`[${modeTag} · ${llmTurnCount} turns] Last: "${reply.slice(0, 50)}${reply.length > 50 ? '…' : ''}"`);
|
||||
|
||||
// Fill say box so user can see what Jibo is about to say
|
||||
document.getElementById('say-text').value = reply;
|
||||
await post('/api/say', { text: reply });
|
||||
const sayResult = await post('/api/say', { text: reply });
|
||||
|
||||
// If the reply ends with a question and wasn't interrupted, listen for the user's answer
|
||||
const endsWithQuestion = /\?[^a-zA-Z0-9]*$/.test(reply.trim());
|
||||
if (endsWithQuestion && !sayResult?.aborted && document.getElementById('llm-toggle').checked) {
|
||||
doListen();
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('btn-llm-cancel').addEventListener('click', () => {
|
||||
post('/api/llm/cancel');
|
||||
llmStatus('Cancelled.');
|
||||
});
|
||||
|
||||
document.getElementById('btn-llm-clear').addEventListener('click', () => {
|
||||
llmHistory = [];
|
||||
llmStatus('Conversation cleared.');
|
||||
llmHistory = [];
|
||||
llmTurnCount = 0;
|
||||
llmStatus(llmSessionMode ? 'Session turn counter reset (server session persists).' : 'Conversation cleared.');
|
||||
});
|
||||
|
||||
// ── Attention ─────────────────────────────────────────────────────────────────
|
||||
@@ -566,26 +590,24 @@ function flashHotword(utterance, score) {
|
||||
hotwordTimer = setTimeout(() => el.classList.remove('active'), 3000);
|
||||
}
|
||||
|
||||
// ── Menu: Robot & Mode Selection ────────────────────────────────────────────
|
||||
// ── Menu: Robot & Mode Selection ─────────────────────────────────────────────
|
||||
|
||||
let selectedRobot = null;
|
||||
let selectedMode = 'commander';
|
||||
let selectedMode = 'commander';
|
||||
|
||||
// Get the selected robot and mode from sessionStorage
|
||||
function initializeMode() {
|
||||
selectedRobot = sessionStorage.getItem('selectedRobot') || 'jibo-001';
|
||||
selectedMode = sessionStorage.getItem('selectedMode') || 'commander';
|
||||
selectedMode = sessionStorage.getItem('selectedMode') || 'commander';
|
||||
}
|
||||
|
||||
// Back to home button
|
||||
document.getElementById('btn-back-home')?.addEventListener('click', () => {
|
||||
window.location.href = 'index.html';
|
||||
});
|
||||
|
||||
// ── Initialization ───────────────────────────────────────────────────────────
|
||||
// ── Init ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
connectWS();
|
||||
initializeMode();
|
||||
connectWS();
|
||||
|
||||
// Populate LLM fields from server config (.env defaults)
|
||||
get('/api/config').then(cfg => {
|
||||
@@ -593,4 +615,8 @@ get('/api/config').then(cfg => {
|
||||
if (cfg.llmEndpoint) document.getElementById('llm-endpoint').value = cfg.llmEndpoint;
|
||||
if (cfg.llmModel) document.getElementById('llm-model').value = cfg.llmModel;
|
||||
if (cfg.llmSystemPrompt) document.getElementById('llm-system-prompt').value = cfg.llmSystemPrompt;
|
||||
if (cfg.sessionMode) {
|
||||
llmSessionMode = true;
|
||||
llmStatus('Session mode (OpenClaw) — history managed server-side.');
|
||||
}
|
||||
});
|
||||
@@ -253,11 +253,11 @@
|
||||
<span class="mode-icon">🎮</span>
|
||||
<span class="mode-label">Commander</span>
|
||||
</button>
|
||||
<button class="mode-btn" data-mode="animator" title="Animator Mode">
|
||||
<button class="mode-btn" data-mode="animator" title="Animator Mode" style="display:none;">
|
||||
<span class="mode-icon">🎬</span>
|
||||
<span class="mode-label">Animator</span>
|
||||
</button>
|
||||
<button class="mode-btn" data-mode="telepresence" title="Telepresence Mode">
|
||||
<button class="mode-btn" data-mode="telepresence" title="Telepresence Mode" style="display:none;">
|
||||
<span class="mode-icon">👁</span>
|
||||
<span class="mode-label">Telepresence</span>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user