next: ai part 2

This commit is contained in:
nym21
2026-07-22 16:50:27 +02:00
parent 227a31f64e
commit 52e4db5ea6
18 changed files with 1318 additions and 1281 deletions
+120
View File
@@ -0,0 +1,120 @@
import { ASK_MODEL } from "../models.js";
/** @param {number} bytes */
function formatBytes(bytes) {
return bytes >= 1_000_000
? `${(bytes / 1_000_000).toFixed(0)} MB`
: `${(bytes / 1_000).toFixed(0)} KB`;
}
/** @param {{ onLoad: () => void }} options */
export function createAskLoader(options) {
const loader = document.createElement("section");
const load = document.createElement("button");
const label = document.createElement("span");
const detail = document.createElement("small");
const progress = document.createElement("progress");
const status = document.createElement("p");
loader.dataset.askLoader = "";
load.type = "button";
load.addEventListener("click", options.onLoad);
label.append("Download & use");
detail.append(ASK_MODEL.size);
load.append(label, detail);
progress.max = 100;
progress.hidden = true;
status.role = "status";
status.ariaLive = "polite";
status.hidden = true;
loader.append(load, progress, status);
/** @param {string} message */
function showStatus(message) {
status.hidden = !message;
status.textContent = message;
}
return {
element: loader,
checking() {
loader.hidden = false;
load.hidden = true;
progress.hidden = false;
progress.removeAttribute("value");
showStatus("Checking browser cache...");
},
/** @param {string | undefined} [message] */
unloaded(message) {
loader.hidden = false;
load.hidden = false;
load.disabled = false;
label.textContent = "Download & use";
detail.textContent = ASK_MODEL.size;
progress.hidden = true;
showStatus(message ?? "");
},
/** @param {boolean} cached */
loading(cached) {
loader.hidden = false;
load.hidden = true;
progress.hidden = false;
if (cached) progress.removeAttribute("value");
else progress.value = 0;
showStatus(
cached
? "Loading the model from browser storage..."
: "Preparing the one-time local download...",
);
},
/** @param {string} message */
loadError(message) {
loader.hidden = false;
load.hidden = false;
load.disabled = false;
label.textContent = "Try again";
progress.hidden = true;
showStatus(`Load failed · ${message}`);
},
ready() {
loader.hidden = true;
},
/** @param {string} message */
answerError(message) {
loader.hidden = false;
load.hidden = true;
progress.hidden = true;
showStatus(`Could not answer · ${message}`);
},
/**
* @param {{ progress: number, loaded: number, total: number }} update
* @param {boolean} cached
*/
reportProgress(update, cached) {
if (!cached) {
progress.hidden = false;
progress.value = update.progress;
}
showStatus(
update.total
? cached
? "Loading the model from browser storage..."
: `Downloading ${formatBytes(update.loaded)} of ${formatBytes(update.total)}...`
: cached
? "Starting the cached model..."
: `Downloading model... ${update.progress.toFixed(0)}%`,
);
},
/**
* @param {string} message
* @param {boolean} cached
*/
reportStatus(message, cached) {
showStatus(
cached && message.includes("Downloading")
? "Loading the model from browser storage..."
: message,
);
},
};
}
+57
View File
@@ -0,0 +1,57 @@
main[data-page="ask"] [data-ask-loader] {
display: grid;
gap: 0.5rem;
> button {
display: grid;
grid-template-columns: minmax(0, 1fr) auto;
align-items: center;
gap: 0.75rem;
width: 100%;
border-radius: var(--control-radius);
padding: var(--control-padding);
text-align: left;
text-transform: none;
> small {
color: inherit;
font-size: var(--font-size-xs);
opacity: 0.55;
}
}
> progress {
appearance: none;
width: 100%;
height: 0.2rem;
border: 0;
border-radius: 999px;
overflow: hidden;
background: color-mix(in oklch, var(--white) 10%, transparent);
accent-color: var(--orange);
&::-webkit-progress-bar {
border-radius: inherit;
background: color-mix(in oklch, var(--white) 10%, transparent);
}
&::-webkit-progress-value {
border-radius: inherit;
background: var(--orange);
}
&::-moz-progress-bar {
border-radius: inherit;
background: var(--orange);
}
}
> p {
margin: 0;
color: color-mix(in oklch, var(--white) 42%, transparent);
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
text-align: center;
overflow-wrap: anywhere;
}
}