enCoder commited on
Commit
4fa42d8
·
1 Parent(s): 9dfe9bd

Implement replay mode enhancements and run-locally instructions

Browse files

- Updated `app.js` to allow sending prompts in replay mode while providing a hint for running the server locally.
- Added a new `run-locally` section in `index.html` with instructions and buttons for copying commands and dismissing the hint.
- Enhanced `style.css` to style the run-locally callout and added visual cues for replay-locked buttons.
- Improved user experience by keeping the textarea editable in replay mode while disabling actual submissions.

Files changed (3) hide show
  1. web/app.js +42 -8
  2. web/index.html +13 -1
  3. web/style.css +36 -1
web/app.js CHANGED
@@ -81,11 +81,18 @@ function setMode(mode) {
81
  ui.connection.textContent = "replay";
82
  ui.connection.classList.remove("offline");
83
  ui.connection.classList.add("replay");
84
- ui.send.disabled = true;
85
- ui.sendTwice.disabled = true;
86
- ui.prompt.disabled = true;
 
 
 
 
 
 
 
87
  setBanner(
88
- "REPLAY MODE — this is a pre-recorded session. Run the server locally to send your own prompts.",
89
  "replay-banner",
90
  );
91
  if (ui.speed) ui.speed.style.display = "";
@@ -412,15 +419,42 @@ async function sendPrompt(prompt) {
412
  }
413
  }
414
 
415
- ui.send.addEventListener("click", () => sendPrompt(ui.prompt.value));
416
- ui.sendTwice.addEventListener("click", async () => {
 
 
 
 
 
 
 
 
 
 
 
 
417
  const p = ui.prompt.value;
418
  await sendPrompt(p);
419
  await new Promise(r => setTimeout(r, 200));
420
  await sendPrompt(p);
421
- });
422
  ui.prompt.addEventListener("keydown", (e) => {
423
- if ((e.metaKey || e.ctrlKey) && e.key === "Enter") sendPrompt(e.target.value);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
424
  });
425
 
426
  if (ui.speed) ui.speed.addEventListener("change", () => {
 
81
  ui.connection.textContent = "replay";
82
  ui.connection.classList.remove("offline");
83
  ui.connection.classList.add("replay");
84
+ // Keep textarea editable — feels alive — but the Send buttons can't
85
+ // really submit, so they open the run-locally hint instead.
86
+ ui.send.disabled = false;
87
+ ui.sendTwice.disabled = false;
88
+ ui.prompt.disabled = false;
89
+ ui.send.classList.add("replay-locked");
90
+ ui.sendTwice.classList.add("replay-locked");
91
+ ui.send.title = "Replay mode — click to see how to run live locally";
92
+ ui.sendTwice.title = ui.send.title;
93
+ ui.prompt.placeholder = "Recorded demo — typing won't submit. Run the server locally to use your own prompts.";
94
  setBanner(
95
+ "REPLAY MODE — this is a pre-recorded session. Send buttons show local-run instructions instead.",
96
  "replay-banner",
97
  );
98
  if (ui.speed) ui.speed.style.display = "";
 
419
  }
420
  }
421
 
422
+ function showRunLocally() {
423
+ const el = $("run-locally");
424
+ if (!el) return;
425
+ el.hidden = false;
426
+ el.scrollIntoView({ behavior: "smooth", block: "nearest" });
427
+ }
428
+
429
+ function trySend(handler) {
430
+ if (state.mode !== "live") { showRunLocally(); return; }
431
+ handler();
432
+ }
433
+
434
+ ui.send.addEventListener("click", () => trySend(() => sendPrompt(ui.prompt.value)));
435
+ ui.sendTwice.addEventListener("click", () => trySend(async () => {
436
  const p = ui.prompt.value;
437
  await sendPrompt(p);
438
  await new Promise(r => setTimeout(r, 200));
439
  await sendPrompt(p);
440
+ }));
441
  ui.prompt.addEventListener("keydown", (e) => {
442
+ if ((e.metaKey || e.ctrlKey) && e.key === "Enter") trySend(() => sendPrompt(e.target.value));
443
+ });
444
+
445
+ // Run-locally callout controls.
446
+ const rlClose = $("rl-close");
447
+ if (rlClose) rlClose.addEventListener("click", () => { $("run-locally").hidden = true; });
448
+ const rlCopy = $("rl-copy");
449
+ if (rlCopy) rlCopy.addEventListener("click", async () => {
450
+ const cmd = $("run-locally").querySelector("pre").innerText.trim();
451
+ try {
452
+ await navigator.clipboard.writeText(cmd);
453
+ rlCopy.textContent = "Copied ✓";
454
+ setTimeout(() => { rlCopy.textContent = "Copy command"; }, 1500);
455
+ } catch {
456
+ rlCopy.textContent = "Copy failed";
457
+ }
458
  });
459
 
460
  if (ui.speed) ui.speed.addEventListener("change", () => {
web/index.html CHANGED
@@ -58,6 +58,18 @@
58
  <button id="restart" style="display:none" class="ghost">Restart</button>
59
  </span>
60
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
61
  </section>
62
 
63
  <main>
@@ -94,7 +106,7 @@
94
  </main>
95
 
96
  <footer>
97
- Subscribed to <code>/engine/events</code> · Source on <a href="https://github.com/surajsharan/tiny_vLLM" target="_blank" rel="noopener">github.com/surajsharan/tiny_vLLM</a> · Designed to match <a href="https://surajsharan.github.io/">surajsharan.github.io</a>.
98
  </footer>
99
 
100
  <script src="app.js"></script>
 
58
  <button id="restart" style="display:none" class="ghost">Restart</button>
59
  </span>
60
  </div>
61
+
62
+ <div id="run-locally" class="run-locally" hidden>
63
+ <div class="rl-head">This is a <b>recorded</b> session — to send live prompts, run the server locally.</div>
64
+ <pre><code>git clone https://github.com/surajsharan/tiny_vLLM
65
+ cd tiny_vLLM &amp;&amp; pip install -r requirements.txt
66
+ python -m tiny_vllm.server --model Qwen/Qwen2.5-0.5B-Instruct
67
+ # then open http://localhost:8000</code></pre>
68
+ <div class="rl-foot">
69
+ <button id="rl-copy" class="ghost">Copy command</button>
70
+ <button id="rl-close" class="ghost">Dismiss</button>
71
+ </div>
72
+ </div>
73
  </section>
74
 
75
  <main>
 
106
  </main>
107
 
108
  <footer>
109
+ Subscribed to <code>/engine/events</code> · Source on <a href="https://github.com/surajsharan/tiny_vLLM" target="_blank" rel="noopener">github.com/surajsharan/tiny_vLLM</a>
110
  </footer>
111
 
112
  <script src="app.js"></script>
web/style.css CHANGED
@@ -183,7 +183,12 @@ button {
183
  transition: all 0.12s ease;
184
  }
185
  button:hover { background: var(--accent-dim); border-color: var(--accent-dim); }
186
- button:disabled { opacity: 0.35; cursor: not-allowed; background: var(--bg-elev); color: var(--muted); border-color: var(--border); }
 
 
 
 
 
187
  button.ghost {
188
  background: transparent;
189
  border: 1px solid var(--border-strong);
@@ -198,6 +203,36 @@ button.ghost:hover { border-color: var(--accent); color: var(--accent); }
198
 
199
  textarea:disabled { opacity: 0.5; }
200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  .replay-controls { margin-left: auto; display: flex; gap: 6px; align-items: center; }
202
  .replay-controls select {
203
  background: var(--bg); color: var(--fg);
 
183
  transition: all 0.12s ease;
184
  }
185
  button:hover { background: var(--accent-dim); border-color: var(--accent-dim); }
186
+ button:disabled { opacity: 0.55; cursor: not-allowed; background: var(--bg-elev); color: var(--muted); border-color: var(--border); }
187
+ /* Replay-mode "soft disable": looks clickable, but Send opens the run-locally
188
+ * hint instead of submitting. We mark it with a class so the cursor and
189
+ * tooltip read as intentional, not broken. */
190
+ button.replay-locked { cursor: help; }
191
+ button.replay-locked::after { content: " ✦"; color: var(--purple); }
192
  button.ghost {
193
  background: transparent;
194
  border: 1px solid var(--border-strong);
 
203
 
204
  textarea:disabled { opacity: 0.5; }
205
 
206
+ /* ---------- run-locally callout (replay mode) ---------- */
207
+ .run-locally {
208
+ margin-top: 4px;
209
+ background: var(--bg);
210
+ border: 1px solid var(--border-strong);
211
+ border-left: 2px solid var(--purple);
212
+ border-radius: var(--radius);
213
+ padding: 12px 14px;
214
+ font-family: var(--mono);
215
+ font-size: 12px;
216
+ }
217
+ .run-locally[hidden] { display: none; }
218
+ .run-locally .rl-head {
219
+ color: var(--fg);
220
+ font-size: 12px;
221
+ margin-bottom: 8px;
222
+ }
223
+ .run-locally .rl-head b { color: var(--purple); font-weight: 600; }
224
+ .run-locally pre {
225
+ margin: 0 0 10px;
226
+ padding: 10px 12px;
227
+ background: var(--bg-elev2);
228
+ border: 1px solid var(--border);
229
+ border-radius: var(--radius);
230
+ font-family: var(--mono); font-size: 12px;
231
+ color: var(--accent);
232
+ overflow-x: auto;
233
+ }
234
+ .run-locally .rl-foot { display: flex; gap: 8px; }
235
+
236
  .replay-controls { margin-left: auto; display: flex; gap: 6px; align-items: center; }
237
  .replay-controls select {
238
  background: var(--bg); color: var(--fg);