map-annotation-tool / static-bootstrap.js
marijanic's picture
Pin final MapPool dataset revision
01b427f verified
Raw History Blame Contribute Delete
3.19 kB
const vars = globalThis.huggingface?.variables || {};
const datasetId = vars.HF_DATASET_ID || "marijanic/map-annotation-tool-data";
const revision = vars.HF_DATASET_REVISION || "ddf36b53ec5e8eeefcfc41d9923f97d5ec7ac62f";
const manifestName = vars.FIGURE_MANIFEST_PATH || "figures.jsonl";
const datasetBase = `https://huggingface.co/datasets/${datasetId}/resolve/${revision}/`;
const root = document.getElementById("mat-root");
const encodePath = path => path.split("/").map(encodeURIComponent).join("/");
const digest = async bytes => Array.from(new Uint8Array(await crypto.subtle.digest("SHA-256", bytes)))
.map(value => value.toString(16).padStart(2, "0")).join("");
const stable = value => {
if (value === null || typeof value !== "object") return JSON.stringify(value);
if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`;
return `{${Object.keys(value).sort().map(key => `${JSON.stringify(key)}:${stable(value[key])}`).join(",")}}`;
};
const parseJsonl = text => text.split(/\r?\n/).filter(line => line.trim()).map(line => JSON.parse(line));
const fetchBytes = async url => {
const response = await fetch(url);
if (!response.ok) throw new Error(`${response.status} while loading ${url}`);
return new Uint8Array(await response.arrayBuffer());
};
const decode = bytes => new TextDecoder().decode(bytes);
const resolveCanonicalUrl = value => {
if (!value) return datasetBase + "annotations.jsonl";
if (value.startsWith("local:")) {
const path = value.slice("local:".length);
return new URL(path, document.baseURI).href;
}
return value;
};
try {
const manifestUrl = datasetBase + encodePath(manifestName);
const canonicalUrl = resolveCanonicalUrl(vars.CANONICAL_ANNOTATIONS_URL);
const [template, manifestBytes, canonicalBytes] = await Promise.all([
fetch("app/static/component.html").then(response => {
if (!response.ok) throw new Error(`${response.status} while loading the interface`);
return response.text();
}),
fetchBytes(manifestUrl),
fetchBytes(canonicalUrl),
]);
const figures = parseJsonl(decode(manifestBytes));
const records = parseJsonl(decode(canonicalBytes));
for (const figure of figures) {
figure.media_url = datasetBase + encodePath(figure.media_path);
}
const recordHashes = await Promise.all(records.map(async record => [
`${record.dataset_id}\u001f${record.figure_id}`,
await digest(new TextEncoder().encode(stable(record))),
]));
root.innerHTML = template;
globalThis.MAT_ELEMENT = root;
globalThis.MAT_BOOTSTRAP = {
mode: "hf-static",
dataset: {
id: datasetId,
revision,
manifest_sha256: await digest(manifestBytes),
},
canonical: {
url: canonicalUrl,
sha256: await digest(canonicalBytes),
records,
record_sha256: Object.fromEntries(recordHashes),
},
figures,
github_repository_url: vars.GITHUB_REPOSITORY_URL || "",
};
await import("./app/static/component.js");
} catch (error) {
root.innerHTML = `<main class="load-error"><h1>Map annotation tool</h1><p>Could not load the annotation data.</p><pre></pre></main>`;
root.querySelector("pre").textContent = error.message;
}