model-explorer / js /utils /formatters.js
mr4's picture
Upload 71 files
9bd422a verified
/**
* Formatters - Data formatting utilities
* Provides functions for formatting file names, tensor shapes, file sizes,
* data types, and tensor info for display in the UI.
* Requirements: 2.5, 5.6, 7.3
*/
const Formatters = (function () {
// ─── File Name Formatting ─────────────────────────────────────────────────
/**
* Format a file path into a human-readable display name.
* Strips directory separators and returns only the base file name.
* e.g. "models/jsl/model.onnx" β†’ "model.onnx"
* @param {string} filePath
* @returns {string}
*/
function formatFileName(filePath) {
if (!filePath) return 'Unknown';
const base = filePath.replace(/\\/g, '/').split('/').pop() || filePath;
return base;
}
/**
* Format a model name for display: strip extension and replace
* underscores/hyphens with spaces, then title-case.
* e.g. "my_model.onnx" β†’ "My Model"
* @param {string} filePath
* @returns {string}
*/
function formatModelName(filePath) {
if (!filePath) return 'Unknown';
const base = formatFileName(filePath);
const noExt = base.replace(/\.onnx$/i, '');
return noExt
.replace(/[_-]+/g, ' ')
.replace(/\b\w/g, c => c.toUpperCase());
}
// ─── Tensor Shape Formatting ──────────────────────────────────────────────
/**
* Format a tensor shape array into a readable string.
* Dynamic dimensions (null, -1, 0, or string) are shown as "?".
* e.g. [1, 3, 224, 224] β†’ "[1, 3, 224, 224]"
* e.g. [-1, 3, 224, 224] β†’ "[?, 3, 224, 224]"
* @param {Array<number|string|null>} shape
* @returns {string}
*/
function formatShape(shape) {
if (!Array.isArray(shape) || shape.length === 0) return '[]';
const dims = shape.map(d => {
if (d === null || d === undefined) return '?';
if (typeof d === 'string') return d || '?';
if (typeof d === 'number' && (d < 0 || d === 0)) return '?';
return String(d);
});
return '[' + dims.join(', ') + ']';
}
// ─── File Size Formatting ─────────────────────────────────────────────────
/**
* Format a byte count into a human-readable size string.
* e.g. 1024 β†’ "1.00 KB", 1048576 β†’ "1.00 MB"
* @param {number} bytes
* @param {number} [decimals=2]
* @returns {string}
*/
function formatBytes(bytes, decimals = 2) {
if (bytes == null || isNaN(bytes)) return 'Unknown';
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(Math.abs(bytes)) / Math.log(k));
const idx = Math.min(i, sizes.length - 1);
const value = bytes / Math.pow(k, idx);
return value.toFixed(decimals) + ' ' + sizes[idx];
}
// ─── Data Type Formatting ─────────────────────────────────────────────────
/**
* ONNX data type code β†’ human-readable name mapping.
*/
const DATA_TYPE_MAP = {
0: 'UNDEFINED',
1: 'FLOAT',
2: 'UINT8',
3: 'INT8',
4: 'UINT16',
5: 'INT16',
6: 'INT32',
7: 'INT64',
8: 'STRING',
9: 'BOOL',
10: 'FLOAT16',
11: 'DOUBLE',
12: 'UINT32',
13: 'UINT64',
14: 'COMPLEX64',
15: 'COMPLEX128',
16: 'BFLOAT16',
};
/**
* Format an ONNX data type code or string into a readable label.
* Accepts numeric codes (1–16) or string names.
* @param {number|string} code
* @returns {string}
*/
function formatDataType(code) {
if (code == null) return 'Unknown';
if (typeof code === 'number') {
return DATA_TYPE_MAP[code] || `Type(${code})`;
}
// Already a string β€” normalise to upper-case
const upper = String(code).toUpperCase();
// Check if it matches a known name
const known = Object.values(DATA_TYPE_MAP);
return known.includes(upper) ? upper : code;
}
// ─── Tensor Info Formatting ───────────────────────────────────────────────
/**
* Format a TensorInfo object into a concise one-line description.
* e.g. "input_0: FLOAT [1, 3, 224, 224]"
* @param {{ name: string, shape: Array, dataType: number|string }} tensor
* @returns {string}
*/
function formatTensorInfo(tensor) {
if (!tensor) return 'Unknown';
const name = tensor.name || 'unnamed';
const dtype = formatDataType(tensor.dataType);
const shape = formatShape(tensor.shape);
return `${name}: ${dtype} ${shape}`;
}
/**
* Format element count for an initializer.
* @param {Array<number>} shape
* @returns {number}
*/
function calcElementCount(shape) {
if (!Array.isArray(shape) || shape.length === 0) return 0;
return shape.reduce((acc, d) => acc * (d > 0 ? d : 1), 1);
}
// ─── Number Formatting ────────────────────────────────────────────────────
/**
* Format a large integer with locale-aware thousands separators.
* @param {number} n
* @returns {string}
*/
function formatNumber(n) {
if (n == null || isNaN(n)) return '0';
return n.toLocaleString();
}
// ─── Public API ───────────────────────────────────────────────────────────
return {
formatFileName,
formatModelName,
formatShape,
formatBytes,
formatDataType,
formatTensorInfo,
calcElementCount,
formatNumber,
DATA_TYPE_MAP,
};
})();
// Export for global access in vanilla JS context
window.Formatters = Formatters;