File size: 8,310 Bytes
3132104 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | <!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Live Code Camera Engine</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style>
:root { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; }
body { margin: 0; background: #070910; color: #f6f8ff; }
main { max-width: 1240px; margin: 0 auto; padding: 18px; }
h1 { margin: 0 0 6px; font-size: 28px; }
.sub { color: #aeb9ca; margin-bottom: 14px; }
.grid { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 16px; align-items: start; }
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
video, canvas { width: 100%; background: #111827; border-radius: 16px; border: 1px solid #273142; }
textarea, select, input, button {
width: 100%; box-sizing: border-box; border-radius: 12px; border: 1px solid #2f3a4e;
background: #101827; color: #f5f7fb; padding: 11px; font-size: 15px;
}
button { cursor: pointer; background: #1f6feb; border: none; font-weight: 750; margin-top: 8px; }
button.secondary { background: #2b3445; }
button.danger { background: #8b1e3f; }
pre { white-space: pre-wrap; overflow-wrap: anywhere; background: #05070d; border: 1px solid #273142; padding: 14px; border-radius: 14px; min-height: 220px; max-height: 520px; overflow-y: auto; }
label { display:block; margin: 11px 0 6px; color: #b9c2d0; font-size: 13px; }
.row { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.status { color: #9fb1c7; font-size: 14px; margin-top: 8px; }
.metrics { display:grid; grid-template-columns: repeat(3, 1fr); gap:8px; margin-top:10px; }
.metric { background:#111827; border:1px solid #273142; border-radius:12px; padding:10px; font-size:13px; color:#b9c2d0;}
.metric strong { color:#fff; display:block; font-size:18px; }
</style>
</head>
<body>
<main>
<h1>Live Code Camera Engine</h1>
<div class="sub">Camera + audio transcript stream → evidence compression → multimodal LLM → live code updates.</div>
<div class="grid">
<section>
<video id="video" autoplay playsinline muted></video>
<canvas id="canvas" style="display:none"></canvas>
<div class="row">
<button id="startBtn">Start live engine</button>
<button id="stopBtn" class="danger">Stop</button>
</div>
<div class="row">
<button id="speechBtn" class="secondary">Start speech</button>
<button id="forceBtn" class="secondary">Force synthesize now</button>
</div>
<div class="metrics">
<div class="metric"><strong id="entropy">0</strong>visual entropy</div>
<div class="metric"><strong id="delta">0</strong>frame delta</div>
<div class="metric"><strong id="buffered">0</strong>frames buffered</div>
</div>
<p id="status" class="status">Idle.</p>
</section>
<section>
<label>Mode</label>
<select id="mode">
<option value="continuous_code">continuous_code</option>
<option value="debug_visible_error">debug_visible_error</option>
<option value="derive_pipeline">derive_pipeline</option>
<option value="soft_qr_xlc">soft_qr_xlc</option>
<option value="research_prism">research_prism</option>
</select>
<label>Instruction</label>
<textarea id="instruction" rows="4" placeholder="Example: As I point the camera around, infer what app/code/pipeline should be generated."></textarea>
<label>Live speech transcript</label>
<textarea id="transcript" rows="5" placeholder="Speech transcript appears here if supported. You can type too."></textarea>
<label>Frame interval, milliseconds</label>
<input id="frameMs" value="1200" />
<label>LLM synthesis interval, seconds</label>
<input id="synthSec" value="8" />
</section>
</div>
<h2>Live generated code / reasoning summary</h2>
<pre id="output"></pre>
<h2>Latest receipt</h2>
<pre id="receipt"></pre>
</main>
<script>
const video = document.getElementById("video");
const canvas = document.getElementById("canvas");
const statusEl = document.getElementById("status");
const transcriptEl = document.getElementById("transcript");
const outputEl = document.getElementById("output");
const receiptEl = document.getElementById("receipt");
let stream = null;
let ws = null;
let frameTimer = null;
let recognition = null;
let sessionId = null;
function setStatus(msg) { statusEl.textContent = msg; }
function wsUrl() {
const scheme = location.protocol === "https:" ? "wss" : "ws";
return `${scheme}://${location.host}/ws/live-code`;
}
async function startCamera() {
stream = await navigator.mediaDevices.getUserMedia({
video: { facingMode: "environment", width: { ideal: 1280 }, height: { ideal: 720 } },
audio: true
});
video.srcObject = stream;
}
function connectWs() {
ws = new WebSocket(wsUrl());
ws.onopen = () => setStatus("WebSocket connected.");
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "session") {
sessionId = msg.session_id;
setStatus("Session: " + sessionId);
} else if (msg.type === "frame_ack") {
document.getElementById("entropy").textContent = msg.entropy;
document.getElementById("delta").textContent = msg.delta;
document.getElementById("buffered").textContent = msg.buffered;
} else if (msg.type === "synthesis") {
outputEl.textContent = msg.output + "\n\n---\n\n" + outputEl.textContent;
receiptEl.textContent = JSON.stringify(msg.receipt, null, 2);
setStatus("Live synthesis received.");
} else if (msg.type === "error") {
outputEl.textContent = "ERROR: " + msg.message + "\n\n" + outputEl.textContent;
setStatus("Backend error.");
}
};
ws.onclose = () => setStatus("WebSocket closed.");
}
function captureFrameDataUrl() {
const w = video.videoWidth || 1280;
const h = video.videoHeight || 720;
canvas.width = w;
canvas.height = h;
const ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0, w, h);
return canvas.toDataURL("image/jpeg", 0.74);
}
function sendFrame(force=false) {
if (!ws || ws.readyState !== WebSocket.OPEN) return;
const dataUrl = captureFrameDataUrl();
ws.send(JSON.stringify({
type: "frame",
frame: dataUrl,
transcript: transcriptEl.value,
instruction: document.getElementById("instruction").value,
mode: document.getElementById("mode").value,
auto: true,
force,
synthesis_interval: Number(document.getElementById("synthSec").value || 8)
}));
if (transcriptEl.value.trim()) {
ws.send(JSON.stringify({ type: "transcript", text: transcriptEl.value }));
}
}
async function startLive() {
await startCamera();
connectWs();
const ms = Math.max(300, Number(document.getElementById("frameMs").value || 1200));
frameTimer = setInterval(() => sendFrame(false), ms);
setStatus("Live camera stream active.");
}
function stopLive() {
if (frameTimer) clearInterval(frameTimer);
frameTimer = null;
if (recognition) recognition.stop();
if (stream) {
stream.getTracks().forEach(t => t.stop());
stream = null;
}
if (ws) ws.close();
setStatus("Stopped.");
}
function startSpeech() {
const SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
if (!SpeechRecognition) {
setStatus("SpeechRecognition unavailable in this browser. Type transcript manually.");
return;
}
recognition = new SpeechRecognition();
recognition.lang = "en-US";
recognition.continuous = true;
recognition.interimResults = true;
recognition.onresult = (event) => {
let text = "";
for (let i = 0; i < event.results.length; i++) {
text += event.results[i][0].transcript + " ";
}
transcriptEl.value = text.trim();
};
recognition.onerror = (e) => setStatus("Speech error: " + e.error);
recognition.start();
setStatus("Speech recognition active.");
}
document.getElementById("startBtn").onclick = () => startLive().catch(e => setStatus(e.message));
document.getElementById("stopBtn").onclick = stopLive;
document.getElementById("speechBtn").onclick = startSpeech;
document.getElementById("forceBtn").onclick = () => sendFrame(true);
</script>
</body>
</html>
|