mirror of
https://github.com/myronblair/jarvis
synced 2026-06-30 17:50:23 -05:00
Fix arc reactor capabilities showing blank — fall back to handlers field
This commit is contained in:
+50
-15
@@ -995,6 +995,17 @@ if ($action) {
|
||||
$raw = curl_exec($ch); curl_close($ch);
|
||||
j(json_decode($raw, true) ?: ['error'=>'Arc Reactor unreachable']);
|
||||
|
||||
|
||||
case 'vision_analyze':
|
||||
$id = (int)($_GET['id'] ?? 0); if (!$id) bad('Missing id');
|
||||
$ch = curl_init('http://127.0.0.1:7474/job');
|
||||
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_POST=>true, CURLOPT_TIMEOUT=>5,
|
||||
CURLOPT_POSTFIELDS=>json_encode(['type'=>'vision','payload'=>['screenshot_id'=>$id,'provider'=>'claude'],'priority'=>8,'created_by'=>'admin']),
|
||||
CURLOPT_HTTPHEADER=>['Content-Type: application/json']]);
|
||||
$raw = curl_exec($ch); curl_close($ch);
|
||||
j(json_decode($raw, true) ?: ['error'=>'Arc Reactor unreachable']);
|
||||
break;
|
||||
|
||||
case 'vision_purge':
|
||||
$ch = curl_init('http://127.0.0.1:7474/screenshots/purge');
|
||||
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER=>true, CURLOPT_TIMEOUT=>5, CURLOPT_CUSTOMREQUEST=>'DELETE']);
|
||||
@@ -3120,23 +3131,32 @@ async function loadVision() {
|
||||
|
||||
gallery.innerHTML = shots.map(s => {
|
||||
const shotTs = ts(s.created_at);
|
||||
const has = s.file_size > 0;
|
||||
const hasImg = (s.file_size || 0) > 0;
|
||||
const meth = (s.method || 'unknown').toUpperCase();
|
||||
const dim = s.width && s.height ? `${s.width}×${s.height}` : '';
|
||||
const analysis = (s.vision_analysis || '').substring(0, 180);
|
||||
const rawAnalysis = s.vision_analysis || '';
|
||||
const isFailed = rawAnalysis.startsWith('Vision analysis unavailable');
|
||||
const analysis = isFailed ? '' : rawAnalysis.substring(0, 200);
|
||||
const hasAnalysis = !isFailed && rawAnalysis.length > 0;
|
||||
return `<div style="background:rgba(0,212,255,0.03);border:1px solid var(--border);border-radius:4px;overflow:hidden">
|
||||
<div style="background:rgba(0,212,255,0.06);padding:8px 10px;display:flex;align-items:center;gap:8px">
|
||||
<span style="font-family:var(--mono);font-size:0.65rem;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(s.hostname||'unknown')}</span>
|
||||
<span style="font-family:var(--mono);font-size:0.55rem;color:var(--dim)">${meth}</span>
|
||||
<div style="background:rgba(0,212,255,0.06);padding:8px 10px;display:flex;align-items:center;gap:6px">
|
||||
<span class="dot ${s.hostname?'dot-green':'dot-dim'}" style="flex-shrink:0"></span>
|
||||
<span style="font-family:var(--mono);font-size:0.65rem;font-weight:600;flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${esc(s.hostname||'unknown')}</span>
|
||||
<span style="font-family:var(--mono);font-size:0.5rem;color:var(--text-dim)">${meth}</span>
|
||||
<button class="btn btn-xs" onclick="visionViewScreenshot(${s.id})" style="border-color:var(--cyan);color:var(--cyan)">VIEW</button>
|
||||
<button class="btn btn-xs" onclick="visionDeleteShot(${s.id})">✗</button>
|
||||
<button class="btn btn-xs" onclick="visionReanalyze(${s.id})" title="Re-run Claude vision analysis" style="border-color:var(--yellow);color:var(--yellow)">◈</button>
|
||||
<button class="btn btn-xs" onclick="visionDeleteShot(${s.id})" style="border-color:var(--red);color:var(--red)">✗</button>
|
||||
</div>
|
||||
<div style="padding:8px 10px">
|
||||
${has ? `<div style="background:#060a0e;border:1px solid var(--border);border-radius:3px;padding:5px;margin-bottom:8px;cursor:pointer;font-family:var(--mono);font-size:0.6rem;color:var(--text-dim);text-align:center" onclick="visionViewScreenshot(${s.id})">
|
||||
◈ ${dim ? dim + ' · ' : ''}${Math.round((s.file_size||0)/1024)}KB IMAGE
|
||||
</div>` : '<div style="font-size:0.6rem;color:var(--dim);margin-bottom:6px;font-family:var(--mono)">TEXT SNAPSHOT ONLY</div>'}
|
||||
${analysis ? `<div style="font-size:0.62rem;line-height:1.5;color:var(--text-dim)">${esc(analysis)}${s.vision_analysis?.length>180?'…':''}</div>` : ''}
|
||||
<div style="font-family:var(--mono);font-size:0.55rem;color:var(--border2);margin-top:6px">${shotTs}</div>
|
||||
${hasImg
|
||||
? `<div style="background:#060a0e;border:1px solid var(--border);border-radius:3px;padding:6px;margin-bottom:8px;cursor:pointer;display:flex;align-items:center;gap:8px" onclick="visionViewScreenshot(${s.id})">
|
||||
<span style="font-size:1.2rem">🖥</span>
|
||||
<span style="font-family:var(--mono);font-size:0.6rem;color:var(--text-dim)">${Math.round((s.file_size||0)/1024)}KB · click to view</span>
|
||||
</div>`
|
||||
: '<div style="font-size:0.6rem;color:var(--text-dim);margin-bottom:6px;font-family:var(--mono)">TEXT SNAPSHOT ONLY</div>'}
|
||||
${hasAnalysis
|
||||
? `<div style="font-size:0.62rem;line-height:1.6;color:var(--text);">${esc(analysis)}${rawAnalysis.length>200?'…':''}</div>`
|
||||
: `<div style="font-size:0.6rem;color:var(--text-dim);font-family:var(--mono);font-style:italic">${isFailed?'Analysis failed — credits needed':'No analysis yet — click ◈ to analyze'}</div>`}
|
||||
<div style="font-family:var(--mono);font-size:0.55rem;color:var(--text-dim);opacity:0.5;margin-top:6px">${shotTs}</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
@@ -3155,12 +3175,26 @@ async function visionViewScreenshot(id) {
|
||||
METHOD: ${esc(d.method||'')} · ${d.width&&d.height?d.width+'×'+d.height+' · ':''} ${Math.round((d.file_size||0)/1024)}KB · ${ts(d.created_at)}
|
||||
</div>
|
||||
${imgHtml}
|
||||
${d.vision_analysis ? `<div style="font-size:0.55rem;letter-spacing:2px;color:var(--dim);margin-bottom:6px">VISION ANALYSIS</div>
|
||||
<pre style="white-space:pre-wrap;font-size:0.65rem;line-height:1.6;color:var(--text);background:rgba(0,212,255,0.04);border:1px solid var(--border);padding:10px;border-radius:3px;max-height:300px;overflow-y:auto">${esc(d.vision_analysis)}</pre>` : ''}
|
||||
${d.vision_analysis && !d.vision_analysis.startsWith('Vision analysis unavailable') ? `
|
||||
<div style="font-size:0.55rem;letter-spacing:2px;color:var(--text-dim);margin-bottom:6px">◈ VISION ANALYSIS</div>
|
||||
<pre style="white-space:pre-wrap;font-size:0.65rem;line-height:1.6;color:var(--text);background:rgba(0,212,255,0.04);border:1px solid var(--border);padding:10px;border-radius:3px;max-height:300px;overflow-y:auto">${esc(d.vision_analysis)}</pre>` :
|
||||
`<div style="font-size:0.6rem;color:var(--text-dim);font-family:var(--mono);padding:8px 0">No analysis — click ◈ in gallery to analyze when credits are available.</div>`}
|
||||
`, null, null);
|
||||
document.getElementById('modalSave').style.display = 'none';
|
||||
}
|
||||
|
||||
|
||||
async function visionReanalyze(id) {
|
||||
toast('Submitting vision analysis job...', 'ok');
|
||||
const d = await api('vision_analyze', {id});
|
||||
if (d && d.job_id) {
|
||||
toast('Analysis job #' + d.job_id + ' queued', 'ok');
|
||||
setTimeout(() => loadVision(), 8000);
|
||||
} else {
|
||||
toast((d && d.error) || 'Failed — Arc offline or no credits', 'err');
|
||||
}
|
||||
}
|
||||
|
||||
async function visionRunScreenshot() {
|
||||
let agents = _visionAgents.length ? _visionAgents : null;
|
||||
if (!agents) {
|
||||
@@ -4548,7 +4582,8 @@ async function loadArc() {
|
||||
document.getElementById('arc-done-val').textContent = s?.jobs_done ?? s?.stats?.done ?? '—';
|
||||
document.getElementById('arc-fail-val').textContent = s?.jobs_failed ?? s?.stats?.failed ?? '—';
|
||||
document.getElementById('arc-hb-val').textContent = s?.last_heartbeat ? ts(s.last_heartbeat) : (online ? 'ALIVE' : '—');
|
||||
document.getElementById('arc-caps-val').textContent = Array.isArray(s?.capabilities) ? s.capabilities.join(' · ') : (s?.capabilities || '—');
|
||||
const caps = s?.capabilities || s?.handlers;
|
||||
document.getElementById('arc-caps-val').textContent = Array.isArray(caps) ? caps.join(' · ') : (caps || '—');
|
||||
|
||||
const list = Array.isArray(jobs) ? jobs : (jobs?.jobs || []);
|
||||
if (!list.length) {
|
||||
|
||||
Reference in New Issue
Block a user