demos / util.js
Yang Gu
Add gallery mode
80fd73c
"use strict";
function updateGetModelProgress(name, loaded, total) {
const progressElement = document.getElementById('model-progress');
if (total === 0) {
progressElement.innerHTML = `Model ${name} is already in local cache`;
return;
}
const percent = ((loaded / total) * 100).toFixed(2);
let progress;
if (loaded >= total) {
progress = "Downloaded";
} else {
progress = "Downloading";
}
progressElement.innerHTML = `${progress} model ${name}: Total ${total} bytes, loaded ${loaded} bytes, ${percent}%`;
}
// Get model via Origin Private File System
async function getModelOPFS(name, url, updateModel) {
const root = await navigator.storage.getDirectory();
let fileHandle;
async function updateFile() {
const response = await fetch(url);
const buffer = await readResponse(name, response, updateGetModelProgress);
fileHandle = await root.getFileHandle(name, { create: true });
const writable = await fileHandle.createWritable();
await writable.write(buffer);
await writable.close();
return buffer;
}
if (updateModel) {
return await updateFile();
}
try {
fileHandle = await root.getFileHandle(name);
const blob = await fileHandle.getFile();
updateGetModelProgress(name, 0, 0);
return await blob.arrayBuffer();
} catch (e) {
return await updateFile();
}
}
async function readResponse(name, response, progressCallback) {
const contentLength = response.headers.get('Content-Length');
let total = parseInt(contentLength ?? '0');
let buffer = new Uint8Array(total);
let loaded = 0;
const reader = response.body.getReader();
async function read() {
const { done, value } = await reader.read();
if (done) return;
let newLoaded = loaded + value.length;
if (newLoaded > total) {
total = newLoaded;
let newBuffer = new Uint8Array(total);
newBuffer.set(buffer);
buffer = newBuffer;
}
buffer.set(value, loaded);
loaded = newLoaded;
if (progressCallback) {
progressCallback(name, loaded, total);
}
return read();
}
await read();
return buffer;
}
function isInternal() {
if (window.location.href.includes('intel')) {
return true;
} else {
return false;
}
}
function getModelsPath() {
if (isInternal()) {
return "https://wp-27.sh.intel.com/workspace/project/models/";
} else {
return "https://huggingface.co/webai-community/models/resolve/main/";
}
}
function getParam(name, type, _default) {
name = name.replace(/[\[\]]/g, "\\$&");
let regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)", "i");
let results = regex.exec(window.location.href);
if (!results || !results[2]) return _default;
const result = decodeURIComponent(results[2].replace(/\+/g, " "));
if (type === "Boolean") {
if (result === "true") {
return true;
} else if (result === "false") {
return false;
}
} else if (type === "Number") {
return parseInt(result);
} else {
return result;
}
}
async function loadOrt() {
const ortUrl = getParam("ortUrl", "String", "default");
if (ortUrl !== "default") {
await loadScript(ortUrl);
} else if (isInternal()) {
await loadScript("https://wp-27.sh.intel.com/workspace/project/onnxruntime/js/web/dist/ort.webgpu.min.js");
} else {
await loadScript("https://cdn.jsdelivr.net/npm/onnxruntime-web@dev/dist/ort.webgpu.min.js");
}
}
async function loadScript(url) {
return new Promise((resolve, reject) => {
const script = document.createElement('script');
script.onload = resolve;
script.onerror = reject;
script.src = url;
if (url.startsWith('http')) {
script.crossOrigin = 'anonymous';
}
document.body.append(script);
})
}
/*
const webgpuCanvas = new OffscreenCanvas(canvasWidth, canvasHeight);
const webglCanvas = new OffscreenCanvas(canvasWidth, canvasHeight);
const gl = webglCanvas.getContext('webgl2');
const webglTexture = gl.createTexture();
*/
function readGPUBufferSync(buffer, byteOffset, webgpuCanvas, gl, glTexture, device) {
const bufferSize = buffer.size;
const dataBytes = bufferSize - byteOffset;
const canvasWidth = 8192;
const canvasHeight = dataBytes / 4 / canvasWidth + 1;
// Copy WebGPU buffer to WebGPU texture
const webgpuContext = webgpuCanvas.getContext('webgpu');
webgpuContext.configure({
device: device,
format: 'rgb8unorm',
usage: GPUTextureUsage.COPY_DST,
alphaMode: 'premultiplied',
});
const webgpuTexture = webgpuContext.getCurrentTexture();
const bytesPerRow = canvasWidth * 4;
const commandEncoder = device.createCommandEncoder();
commandEncoder.copyBufferToTexture(
{
buffer,
bytesPerRow,
byteOffset,
},
{
webgpuTexture,
},
{
canvasWidth,
canvasHeight,
});
device.queue.submit([commandEncoder.finish()]);
commandEncoder = null;
// Read WebGPU texture via WebGL
gl.bindTexture(gl.TEXTURE_2D, webglTexture);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA8, gl.RGBA, gl.UNSIGNED_BYTE, webgpuCanvas);
gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer());
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, webglTexture, 0);
const pixels = new Uint8Array(dataBytes);
gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
return pixels;
}