marinarosa's picture
Fix space dropdown swap target, add next-step arrow cue
f79d783
Raw
History Blame Contribute Delete
2.9 kB
/* bridge.js β€” glue between htmx fragments and the Gradio-queued GPU endpoint.
*
* htmx handles the plain routes (/ui/spaces, /ui/check). The LLM review runs
* behind Gradio's queue (ZeroGPU token handshake), which htmx can't speak β€”
* so when a fresh #step-review block lands in the DOM we open a @gradio/client
* stream and swap each yielded HTML chunk into #review-body. Pattern borrowed
* from vivamais.
*/
import { Client } from "/static/vendor/gradio-client.min.js";
let clientPromise = null;
function getClient() {
if (!clientPromise) clientPromise = Client.connect(window.location.origin);
return clientPromise;
}
async function streamReview(block) {
const space = block.dataset.space;
const model = block.dataset.model;
block.dataset.state = "streaming";
try {
const client = await getClient();
const job = client.submit("/review", [space, model]);
for await (const msg of job) {
if (msg.type === "data" && typeof msg.data?.[0] === "string") {
htmx.swap("#review-body", msg.data[0], { swapStyle: "outerHTML" });
}
}
block.dataset.state = "done";
const title = document.getElementById("review-title");
if (title) title.textContent = title.textContent.replace(/ is reading.*/, "'s review");
} catch (err) {
block.dataset.state = "error";
htmx.swap(
"#review-body",
`<div id="review-body" class="review__body" data-state="error"><p>` +
`The reviewer model napped through this one (${String(err).slice(0, 120)}). ` +
`The rule check above is still solid β€” try the review again in a moment.</p></div>`,
{ swapStyle: "outerHTML" },
);
}
}
/* Floating arrow that walks the user from step 1 down to step 2; it leaves
* once the review block scrolls into view. */
function armNextStepCue() {
const cue = document.getElementById("next-step-cue");
const review = document.getElementById("step-review");
if (!cue || !review) return;
cue.addEventListener("click", () =>
review.scrollIntoView({ behavior: "smooth", block: "start" }),
);
new IntersectionObserver(
(entries, obs) => {
if (entries.some((e) => e.isIntersecting)) {
cue.remove();
obs.disconnect();
}
},
{ threshold: 0.35 },
).observe(review);
}
/* Whenever htmx swaps in new content, look for a waiting review block. */
document.body.addEventListener("htmx:afterSwap", () => {
const block = document.querySelector('#step-review[data-state="waiting"]');
if (block) {
streamReview(block);
armNextStepCue();
}
});
/* Free-text space input wins over the dropdown. */
document.body.addEventListener("htmx:configRequest", (evt) => {
if (evt.detail.elt?.id !== "check-form") return;
const typed = (evt.detail.parameters.space_text || "").trim();
if (typed) evt.detail.parameters.space = typed;
delete evt.detail.parameters.space_text;
});