Skip to content

Instantly share code, notes, and snippets.

@cyberofficial
Last active October 22, 2025 09:54
Show Gist options
  • Select an option

  • Save cyberofficial/0dd5ed0bd229433563bec9a658f5f16a to your computer and use it in GitHub Desktop.

Select an option

Save cyberofficial/0dd5ed0bd229433563bec9a658f5f16a to your computer and use it in GitHub Desktop.

Simple token tracker for vultr Serverless Inference Track your token use and current session.

Preview

image
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vultr Inference Usage Monitor</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
padding: 20px;
}
.container {
background: white;
border-radius: 15px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
padding: 40px;
max-width: 800px;
width: 100%;
}
.test-mode {
background: #fffbe6;
border: 2px solid #ffa500;
color: #ff8c00;
padding: 12px;
border-radius: 8px;
text-align: center;
font-weight: bold;
margin-bottom: 20px;
display: none;
}
h1 {
text-align: center;
color: #333;
font-size: 32px;
margin-bottom: 10px;
}
.timestamp {
text-align: center;
color: #666;
font-size: 14px;
margin-bottom: 30px;
}
.info-section {
margin-bottom: 25px;
}
.label {
color: #555;
font-size: 16px;
margin-bottom: 8px;
}
.progress-bar {
width: 100%;
height: 35px;
background: #e0e0e0;
border-radius: 17px;
overflow: hidden;
position: relative;
margin-bottom: 15px;
}
.progress-fill {
height: 100%;
background: linear-gradient(90deg, #4caf50 0%, #45a049 100%);
transition: width 0.5s ease, background 0.3s ease;
border-radius: 17px;
}
.progress-fill.overage {
background: linear-gradient(90deg, #f44336 0%, #d32f2f 100%);
}
.separator {
height: 2px;
background: #ddd;
margin: 30px 0;
}
.total-cost {
text-align: center;
font-size: 24px;
font-weight: bold;
color: #9c27b0;
padding: 20px;
background: #f5f5f5;
border-radius: 10px;
margin-top: 20px;
}
.error {
color: #f44336;
text-align: center;
padding: 15px;
background: #ffebee;
border-radius: 8px;
margin-bottom: 20px;
display: none;
}
.config-section {
background: #f9f9f9;
padding: 20px;
border-radius: 10px;
margin-bottom: 30px;
}
.config-row {
display: flex;
gap: 20px;
margin-bottom: 15px;
align-items: center;
}
.config-row label {
flex: 0 0 150px;
font-weight: 500;
}
.config-row input {
flex: 1;
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 5px;
font-size: 14px;
}
.config-row button {
padding: 8px 20px;
background: #667eea;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 14px;
transition: background 0.3s;
}
.config-row button:hover {
background: #5568d3;
}
.overage-text {
color: #f44336;
font-weight: bold;
}
.rate-info {
background: #e8f4f8;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
border-left: 4px solid #2196F3;
}
.rate-info .label {
color: #1976D2;
font-weight: 500;
}
.session-section {
background: #f3e5f5;
padding: 20px;
border-radius: 10px;
margin-top: 30px;
border-left: 4px solid #9c27b0;
}
.session-section h3 {
color: #7b1fa2;
margin-bottom: 15px;
}
.session-button {
background: #9c27b0;
color: white;
padding: 10px 25px;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
font-weight: 500;
transition: background 0.3s;
margin-bottom: 15px;
}
.session-button:hover {
background: #7b1fa2;
}
.session-button.stop {
background: #f44336;
}
.session-button.stop:hover {
background: #d32f2f;
}
.session-stats {
display: none;
margin-top: 15px;
}
.session-stats.active {
display: block;
}
.stat-row {
padding: 8px 0;
border-bottom: 1px solid #e1bee7;
}
.stat-row:last-child {
border-bottom: none;
}
.stat-label {
font-weight: 500;
color: #7b1fa2;
}
.stat-value {
color: #555;
margin-left: 10px;
}
</style>
</head>
<body>
<div class="container">
<div class="test-mode" id="testModeAlert"></div>
<div class="error" id="errorMessage"></div>
<!-- Full JSON Data Details -->
<details id="jsonDetails" style="margin-top:20px;">
<summary style="cursor:pointer;padding:8px 16px;background:#667eea;color:#fff;border:none;border-radius:5px;">Show Full JSON Data</summary>
<div id="jsonContainer" style="margin-top:15px;padding:10px;background:#f5f5f5;border-radius:5px;overflow:auto;max-height:300px;"></div>
</details>
<div class="config-section">
<h3 style="margin-bottom: 15px; color: #333;">Configuration</h3>
<div class="config-row">
<label>API Key:</label>
<input type="password" id="apiKey" placeholder="Enter your Vultr API key">
</div>
<div class="config-row">
<label>Refresh (seconds):</label>
<input type="number" id="refreshInterval" value="5" min="1">
</div>
<div class="config-row">
<label>Test Mode Tokens:</label>
<input type="number" id="testTokens" value="0" min="0" placeholder="0 = use real API">
<button id="startBtn" onclick="startMonitoring()">Start Monitoring</button>
<button id="stopBtn" onclick="stopMonitoring()" style="background: #f44336; display: none;">Stop Monitoring</button>
</div>
</div>
<h1>Vultr Inference Usage Monitor</h1>
<div class="timestamp" id="timestamp">Last updated: Never</div>
<div class="info-section">
<div class="label" id="tokensLabel">Chat tokens used: 0 / 50,000,000</div>
<div class="progress-bar">
<div class="progress-fill" id="tokenProgress"></div>
</div>
</div>
<div class="info-section">
<div class="label" id="percentLabel">Percentage used: 0.00%</div>
<div class="label" id="remainingLabel">Tokens remaining: 50,000,000</div>
</div>
<div class="separator"></div>
<div class="info-section">
<div class="label" id="proportionalLabel">Proportional value used: $0.0000 of $10.00</div>
<div class="progress-bar">
<div class="progress-fill" id="costProgress"></div>
</div>
</div>
<div class="rate-info">
<div class="label">Base monthly cost: $10.00 (includes 50M tokens)</div>
<div class="label">Cost per 1K tokens over limit: $0.0002</div>
<div class="label">Cost per 1M tokens over limit: $0.20</div>
</div>
<div class="info-section">
<div class="label" id="overageLabel">Total overage cost: $0.0000</div>
</div>
<div class="total-cost" id="totalCost">Total cost this month: $10.00</div>
<div class="session-section">
<h3>Session Tracking</h3>
<button class="session-button" id="sessionBtn" onclick="toggleSessionTracking()">Start Tracking Session</button>
<div class="session-stats" id="sessionStats">
<div class="stat-row">
<span class="stat-label">Session Duration:</span>
<span class="stat-value" id="sessionDuration">0h 0m 0s</span>
</div>
<div class="stat-row">
<span class="stat-label">Tokens Used in Session:</span>
<span class="stat-value" id="sessionTokens">0</span>
</div>
<div class="stat-row">
<span class="stat-label">Session Cost:</span>
<span class="stat-value" id="sessionCost">$0.0000</span>
</div>
</div>
</div>
</div>
<script>
const MONTHLY_LIMIT = 50000000;
const BASE_COST = 10.00;
const OVERAGE_RATE = 0.0002 / 1000;
const API_URL = "https://api.vultrinference.com/v1/usage";
let intervalId = null;
let sessionTracking = false;
let sessionStartTokens = 0;
let sessionStartTime = null;
let sessionIntervalId = null;
function formatNumber(num) {
return new Intl.NumberFormat('en-US').format(num);
}
function showError(message) {
const errorEl = document.getElementById('errorMessage');
errorEl.textContent = 'Error: ' + message;
errorEl.style.display = 'block';
setTimeout(() => {
errorEl.style.display = 'none';
}, 5000);
}
async function fetchUsageData() {
const apiKey = document.getElementById('apiKey').value.trim();
const testTokens = parseInt(document.getElementById('testTokens').value) || 0;
let chatUsed;
if (testTokens > 0) {
chatUsed = testTokens;
const testAlert = document.getElementById('testModeAlert');
testAlert.textContent = `⚠️ TEST MODE ACTIVE - Using simulated token amount: ${formatNumber(testTokens)} ⚠️`;
testAlert.style.display = 'block';
// Simulated full data for test mode
var fullData = {
usage: {
current_month: {
chat: testTokens,
tts: 0,
tts_sm: 0,
image: 0,
image_sm: 0
},
previous_month: {
chat: 0,
tts: 0,
tts_sm: 0,
image: 0,
image_sm: 0
}
}
};
updateJSONTab(fullData);
} else {
if (!apiKey) {
showError('Please enter your API key');
return;
}
document.getElementById('testModeAlert').style.display = 'none';
try {
const response = await fetch(API_URL, {
method: 'GET',
headers: {
'Authorization': `Bearer ${apiKey}`
}
});
if (!response.ok) {
throw new Error(`API request failed: ${response.status}`);
}
const data = await response.json();
chatUsed = parseFloat(data.usage.current_month.chat);
// Store full JSON for secondary tab
updateJSONTab(data);
} catch (error) {
showError(error.message);
return;
}
}
updateUI(chatUsed);
}
// Populate the secondary JSON tab with formatted HTML
function updateJSONTab(data) {
const container = document.getElementById('jsonContainer');
if (!container) return;
// Build HTML representation
const html = renderJSONToHTML(data);
container.innerHTML = html;
// Do NOT auto-open the details; user controls visibility
}
// Convert the JSON usage object into a nice HTML table
function renderJSONToHTML(data) {
if (!data || !data.usage) return '<p>No usage data available.</p>';
const { current_month, previous_month } = data.usage;
// Helper to render a month table
const renderMonth = (monthData, title) => {
let rows = '';
for (const [key, value] of Object.entries(monthData)) {
rows += `
<tr>
<td style="padding:4px 8px;font-weight:500;">${key}</td>
<td style="padding:4px 8px;text-align:right;">${value}</td>
</tr>`;
}
return `
<h4 style="margin:8px 0 4px;color:#333;">${title}</h4>
<table style="width:100%;border-collapse:collapse;margin-bottom:12px;">
<thead>
<tr>
<th style="text-align:left;padding:4px 8px;background:#e0e0e0;">Metric</th>
<th style="text-align:right;padding:4px 8px;background:#e0e0e0;">Count</th>
</tr>
</thead>
<tbody>
${rows}
</tbody>
</table>`;
};
return `
<div style="font-family:Arial,Helvetica,sans-serif;color:#222;">
${renderMonth(current_month, 'Current Month')}
${renderMonth(previous_month, 'Previous Month')}
</div>`;
}
function updateUI(chatUsed) {
const percentUsed = (chatUsed / MONTHLY_LIMIT) * 100;
const tokensRemaining = MONTHLY_LIMIT - chatUsed;
const proportionalValue = (chatUsed / MONTHLY_LIMIT) * BASE_COST;
let totalCost = BASE_COST;
let overCost = 0;
// Update timestamp
const now = new Date();
document.getElementById('timestamp').textContent =
`Last updated: ${now.toLocaleTimeString()}`;
// Update token labels
document.getElementById('tokensLabel').textContent =
`Chat tokens used: ${formatNumber(chatUsed)} / ${formatNumber(MONTHLY_LIMIT)}`;
document.getElementById('percentLabel').textContent =
`Percentage used: ${percentUsed.toFixed(2)}%`;
document.getElementById('remainingLabel').textContent =
`Tokens remaining: ${formatNumber(tokensRemaining)}`;
document.getElementById('proportionalLabel').textContent =
`Proportional value used: $${proportionalValue.toFixed(4)} of $10.00`;
// Update progress bars
const tokenProgress = document.getElementById('tokenProgress');
const costProgress = document.getElementById('costProgress');
const progressPercent = Math.min(percentUsed, 100);
tokenProgress.style.width = progressPercent + '%';
costProgress.style.width = progressPercent + '%';
// Set progress bar color based on usage percentage
let barColor;
if (percentUsed < 75) {
barColor = '#4caf50'; // green
} else if (percentUsed < 85) {
barColor = '#ffeb3b'; // yellow
} else if (percentUsed < 95) {
barColor = '#ff9800'; // orange
} else {
barColor = '#f44336'; // red
}
tokenProgress.style.background = barColor;
costProgress.style.background = barColor;
// Handle overage
const overageLabel = document.getElementById('overageLabel');
if (chatUsed > MONTHLY_LIMIT) {
const overBy = chatUsed - MONTHLY_LIMIT;
overCost = overBy * OVERAGE_RATE;
totalCost += overCost;
overageLabel.innerHTML = `<span class="overage-text">Total overage cost: $${overCost.toFixed(4)} (${formatNumber(overBy)} tokens over limit)</span>`;
tokenProgress.classList.add('overage');
costProgress.classList.add('overage');
} else {
overageLabel.innerHTML = 'Total overage cost: $0.0000';
tokenProgress.classList.remove('overage');
costProgress.classList.remove('overage');
}
// Update total cost
document.getElementById('totalCost').textContent =
`Total cost this month: ${totalCost.toFixed(2)}`;
// Update session tracking if active
if (sessionTracking) {
updateSessionStats(chatUsed);
}
}
function startMonitoring() {
// Clear existing interval
if (intervalId) {
clearInterval(intervalId);
}
// Fetch immediately
fetchUsageData();
// Set up recurring fetch
const refreshSeconds = parseInt(document.getElementById('refreshInterval').value) || 5;
intervalId = setInterval(fetchUsageData, refreshSeconds * 1000);
// Toggle buttons
document.getElementById('startBtn').style.display = 'none';
document.getElementById('stopBtn').style.display = 'inline-block';
}
function stopMonitoring() {
// Clear interval
if (intervalId) {
clearInterval(intervalId);
intervalId = null;
}
// Toggle buttons
document.getElementById('startBtn').style.display = 'inline-block';
document.getElementById('stopBtn').style.display = 'none';
// Update timestamp
document.getElementById('timestamp').textContent = 'Monitoring stopped';
}
function toggleSessionTracking() {
const btn = document.getElementById('sessionBtn');
const stats = document.getElementById('sessionStats');
if (!sessionTracking) {
// Start tracking
sessionTracking = true;
sessionStartTokens = getCurrentTokenCount();
sessionStartTime = new Date();
btn.textContent = 'Stop Tracking Session';
btn.classList.add('stop');
stats.classList.add('active');
// Update session duration every second
sessionIntervalId = setInterval(updateSessionDuration, 1000);
} else {
// Stop tracking
sessionTracking = false;
btn.textContent = 'Start Tracking Session';
btn.classList.remove('stop');
if (sessionIntervalId) {
clearInterval(sessionIntervalId);
sessionIntervalId = null;
}
}
}
function getCurrentTokenCount() {
const text = document.getElementById('tokensLabel').textContent;
const match = text.match(/Chat tokens used: ([\d,]+)/);
if (match) {
return parseInt(match[1].replace(/,/g, ''));
}
return 0;
}
function updateSessionDuration() {
if (!sessionStartTime) return;
const now = new Date();
const diff = Math.floor((now - sessionStartTime) / 1000); // seconds
const hours = Math.floor(diff / 3600);
const minutes = Math.floor((diff % 3600) / 60);
const seconds = diff % 60;
document.getElementById('sessionDuration').textContent =
`${hours}h ${minutes}m ${seconds}s`;
}
function updateSessionStats(currentTokens) {
const tokensUsed = currentTokens - sessionStartTokens;
// Calculate cost
let sessionCost = 0;
let basePortionUsed = 0;
if (tokensUsed <= 0) {
// No tokens used yet or negative (shouldn't happen)
sessionCost = 0;
basePortionUsed = 0;
} else if (sessionStartTokens >= MONTHLY_LIMIT) {
// Started already over limit, all overage
sessionCost = tokensUsed * OVERAGE_RATE;
basePortionUsed = 0;
} else if (currentTokens <= MONTHLY_LIMIT) {
// All within base limit
basePortionUsed = (tokensUsed / MONTHLY_LIMIT) * BASE_COST;
sessionCost = basePortionUsed;
} else {
// Crossed the limit during session
const tokensInBase = MONTHLY_LIMIT - sessionStartTokens;
const tokensInOverage = tokensUsed - tokensInBase;
basePortionUsed = (tokensInBase / MONTHLY_LIMIT) * BASE_COST;
const overageCost = tokensInOverage * OVERAGE_RATE;
sessionCost = basePortionUsed + overageCost;
}
const basePercent = (basePortionUsed / BASE_COST) * 100;
// Update display
document.getElementById('sessionTokens').textContent = formatNumber(tokensUsed);
document.getElementById('sessionCost').textContent = `${sessionCost.toFixed(4)}`;
}
// Auto-start if API key is present (you can remove this if you prefer manual start)
window.addEventListener('load', () => {
const savedKey = ''; // Your key from script
document.getElementById('apiKey').value = savedKey;
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment