// helpers: timing and small utilities
export function nowMs() {
return performance.now();
}
export function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
export function measureAsync(fn) {
const start = nowMs();
return Promise.resolve()
.then(() => fn())
.then(res => ({res, ms: nowMs() - start}));
}
/**
* Log text to a given HTML element with timestamp to show the log in the UI
*
* @param el - HTML element to log to
* @param evt - Event object with job, route, latency, response, and timing metrics
*/
export function logTo(el, evt) {
console.log(evt.job)
if (!el) return;
const row = document.createElement('tr');
row.innerHTML = `
${evt.job.id} |
${new Date().toLocaleTimeString()} |
${evt.route} |
${evt.totalLatency?.toFixed(2) || evt.latency?.toFixed(2) || 0}ms |
${evt.queueingTime?.toFixed(2) || 0}ms |
${evt.inferenceTime?.toFixed(2) || evt.latency?.toFixed(2) || 0}ms |
${escapeHtml(evt.job.prompt.substring(0, 30))}... |
${(evt.response || '').substring(0, 30)} |
${evt.evalRes.exactMatch} |
`;
el.appendChild(row);
el.scrollTop = el.scrollHeight;
}
/**
* Escapes HTML special characters in a string to prevent HTML injection
*
* @param str - Input string
* @returns {string} - Escaped string
*/
function escapeHtml(str) {
return str.replace(/[&<>"']/g, (char) => {
const escapeMap = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": ''',
};
return escapeMap[char];
});
}
/**
* Approximates the number of words in a given text string
*
* @param text - Input text string
* @returns {number} - Approximate number of words
*/
export function getNumberOfWords(text) {
return text.trim().split(/\s+/).length;
}