fdajskldfsljkaf / ocr-api-tester.html
T1ckbase
first commit
5566839
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="color-scheme" content="light dark">
<title>Simple OCR Load Tester</title>
<style>
body {
box-sizing: border-box;
block-size: 100dvh;
margin: 0;
padding: 0.5rem;
font-family: monospace;
}
div {
margin-block-end: 0.25rem;
}
#stats {
padding: 0.25rem;
border: 1px solid gray;
}
.success {
color: green;
}
.fail {
color: red;
}
</style>
</head>
<body>
<h1>OCR API Load Tester (Complex Text)</h1>
<div>
<label>
API URL: <input type="text" id="apiUrl" value="http://localhost:3000/" style="width: 300px;">
</label>
<br>
<label>
Requests: <input type="number" id="reqCount" value="100" style="width: 80px;">
</label>
<br>
<label>
Chars per Image: <input type="number" id="charCount" value="1000" style="width: 80px;">
</label>
<br>
<button onclick="startTest()">Start Test</button>
</div>
<div id="stats">
<strong>Status:</strong> <span id="statusText">Idle</span>
<br>
<strong>Average Duration:</strong> <span id="avgTime">--</span>ms
</div>
<div id="logs"></div>
<script>
// Helper: Generate random string
function generateRandomString(length) {
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ';
let result = '';
for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
// Helper: Create Blob from Canvas with wrapped text
function generateComplexImageBlob(text) {
return new Promise((resolve) => {
const canvas = document.createElement('canvas');
// Larger canvas for more text
canvas.width = 800;
canvas.height = 600;
const ctx = canvas.getContext('2d');
// White background
ctx.fillStyle = '#ffffff';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Text settings
ctx.font = '14px monospace';
ctx.fillStyle = '#000000';
// Simple text wrapping logic
const lineHeight = 20;
const x = 10;
let y = 30;
const maxWidth = 780;
const words = text.split('');
let line = '';
for (let n = 0; n < words.length; n++) {
const testLine = line + words[n];
const metrics = ctx.measureText(testLine);
const testWidth = metrics.width;
if (testWidth > maxWidth && n > 0) {
ctx.fillText(line, x, y);
line = words[n];
y += lineHeight;
} else {
line = testLine;
}
}
ctx.fillText(line, x, y);
canvas.toBlob((blob) => {
resolve(blob);
}, 'image/png');
});
}
// biome-ignore lint: used.
async function startTest() {
const apiUrl = document.getElementById('apiUrl').value;
const reqCount = parseInt(document.getElementById('reqCount').value, 10);
const charCount = parseInt(document.getElementById('charCount').value, 10);
const logsDiv = document.getElementById('logs');
const statusText = document.getElementById('statusText');
const avgTimeSpan = document.getElementById('avgTime');
// Reset UI
logsDiv.innerHTML = '';
avgTimeSpan.innerText = '---';
statusText.innerText = `Running ${reqCount} requests...`;
const durations = [];
const sendRequest = async (index) => {
try {
// 1. Generate Content
const randomText = generateRandomString(charCount);
const blob = await generateComplexImageBlob(randomText);
// 2. Send & Measure
const startTime = performance.now();
const response = await fetch(apiUrl, {
method: 'POST',
headers: { 'Content-Type': 'image/png' },
body: blob,
});
const endTime = performance.now();
const duration = endTime - startTime;
durations.push(duration);
// 3. Log result
const logItem = document.createElement('div');
if (response.ok) {
logItem.className = 'success';
logItem.innerText = `[${index}] OK - ${duration.toFixed(2)}ms`;
} else {
logItem.className = 'fail';
logItem.innerText = `[${index}] FAIL - ${response.status} - ${duration.toFixed(2)}ms`;
}
logsDiv.prepend(logItem); // Newest on top
} catch (error) {
const logItem = document.createElement('div');
logItem.className = 'fail';
logItem.innerText = `[${index}] ERROR - ${error.message}`;
logsDiv.prepend(logItem);
}
};
// Execute all concurrently
const promises = [];
for (let i = 1; i <= reqCount; i++) {
promises.push(sendRequest(i));
}
await Promise.all(promises);
// Calculate Stats
if (durations.length > 0) {
const total = durations.reduce((a, b) => a + b, 0);
const avg = (total / durations.length).toFixed(2);
avgTimeSpan.innerText = avg;
statusText.innerText = 'Completed';
} else {
statusText.innerText = 'Completed (No successful timings)';
}
}
</script>
</body>
</html>