Restore to commit 74e578279624c6045ca440a3459ebfa1f8d54191

This commit is contained in:
southseact-3d
2026-02-07 20:32:41 +00:00
commit ed67b7741b
252 changed files with 99814 additions and 0 deletions

View File

@@ -0,0 +1,328 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Token Usage Test</title>
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 800px;
margin: 40px auto;
padding: 20px;
background: #f5f5f5;
}
.card {
background: white;
padding: 24px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
margin-bottom: 20px;
}
h1 {
margin: 0 0 20px;
color: #333;
}
.controls {
display: flex;
gap: 12px;
margin-bottom: 20px;
flex-wrap: wrap;
}
input[type="number"] {
padding: 8px 12px;
border: 1px solid #ddd;
border-radius: 6px;
flex: 1;
min-width: 150px;
}
button {
padding: 8px 16px;
background: #008060;
color: white;
border: none;
border-radius: 6px;
cursor: pointer;
font-weight: 600;
}
button:hover {
background: #006e51;
}
button:disabled {
background: #ccc;
cursor: not-allowed;
}
.usage-meter {
margin: 20px 0;
}
.usage-header {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
font-size: 14px;
color: #666;
}
.usage-bar {
height: 24px;
background: #e0e0e0;
border-radius: 12px;
overflow: hidden;
position: relative;
}
.usage-fill {
height: 100%;
background: linear-gradient(90deg, #008060, #00a572);
transition: width 0.3s ease;
display: flex;
align-items: center;
justify-content: center;
color: white;
font-size: 12px;
font-weight: 600;
}
.status {
padding: 12px;
border-radius: 6px;
margin-top: 12px;
font-size: 14px;
}
.status.success {
background: #d4edda;
color: #155724;
border: 1px solid #c3e6cb;
}
.status.error {
background: #f8d7da;
color: #721c24;
border: 1px solid #f5c6cb;
}
.status.info {
background: #d1ecf1;
color: #0c5460;
border: 1px solid #bee5eb;
}
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 16px;
margin-top: 20px;
}
.stat {
background: #f8f9fa;
padding: 12px;
border-radius: 8px;
border: 1px solid #e9ecef;
}
.stat-label {
font-size: 12px;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 4px;
}
.stat-value {
font-size: 20px;
font-weight: 700;
color: #333;
}
pre {
background: #f8f9fa;
padding: 12px;
border-radius: 6px;
overflow-x: auto;
font-size: 12px;
margin: 12px 0 0;
}
</style>
</head>
<body>
<div class="card">
<h1>Token Usage Test</h1>
<p>Test the token usage tracking and progress bar updates. This simulates token consumption without actually running AI models.</p>
<div class="controls">
<input type="number" id="tokenAmount" value="1000" min="1" step="100" placeholder="Tokens to add">
<button id="simulateBtn">Simulate Token Usage</button>
<button id="refreshBtn">Refresh Usage</button>
</div>
<div class="usage-meter">
<div class="usage-header">
<span>Monthly Token Usage</span>
<span id="usagePercent"></span>
</div>
<div class="usage-bar">
<div class="usage-fill" id="usageFill" style="width: 0%">
<span id="usageText">0%</span>
</div>
</div>
</div>
<div class="stats">
<div class="stat">
<div class="stat-label">Used</div>
<div class="stat-value" id="usedTokens"></div>
</div>
<div class="stat">
<div class="stat-label">Limit</div>
<div class="stat-value" id="limitTokens"></div>
</div>
<div class="stat">
<div class="stat-label">Remaining</div>
<div class="stat-value" id="remainingTokens"></div>
</div>
<div class="stat">
<div class="stat-label">Plan</div>
<div class="stat-value" id="planName"></div>
</div>
</div>
<div id="statusMessage" style="display: none;"></div>
<pre id="debugOutput" style="display: none;"></pre>
</div>
<script>
const tokenAmountInput = document.getElementById('tokenAmount');
const simulateBtn = document.getElementById('simulateBtn');
const refreshBtn = document.getElementById('refreshBtn');
const usageFill = document.getElementById('usageFill');
const usageText = document.getElementById('usageText');
const usagePercent = document.getElementById('usagePercent');
const usedTokens = document.getElementById('usedTokens');
const limitTokens = document.getElementById('limitTokens');
const remainingTokens = document.getElementById('remainingTokens');
const planName = document.getElementById('planName');
const statusMessage = document.getElementById('statusMessage');
const debugOutput = document.getElementById('debugOutput');
function showStatus(message, type = 'info') {
statusMessage.textContent = message;
statusMessage.className = `status ${type}`;
statusMessage.style.display = 'block';
setTimeout(() => {
statusMessage.style.display = 'none';
}, 5000);
}
function updateUsageDisplay(summary) {
if (!summary) {
showStatus('No usage data available', 'error');
return;
}
const used = summary.used || 0;
const limit = summary.limit || 0;
const percent = summary.percent || 0;
const remaining = summary.remaining || 0;
const plan = summary.plan || 'unknown';
// Update progress bar
usageFill.style.width = `${Math.min(100, percent)}%`;
usageText.textContent = `${percent}%`;
usagePercent.textContent = `${percent}% used`;
// Update stats
usedTokens.textContent = used.toLocaleString();
limitTokens.textContent = limit.toLocaleString();
remainingTokens.textContent = remaining.toLocaleString();
planName.textContent = plan.charAt(0).toUpperCase() + plan.slice(1);
// Change color based on usage
if (percent >= 90) {
usageFill.style.background = 'linear-gradient(90deg, #dc3545, #c82333)';
} else if (percent >= 75) {
usageFill.style.background = 'linear-gradient(90deg, #ffc107, #e0a800)';
} else {
usageFill.style.background = 'linear-gradient(90deg, #008060, #00a572)';
}
debugOutput.textContent = JSON.stringify(summary, null, 2);
debugOutput.style.display = 'block';
}
async function fetchUsage() {
try {
const response = await fetch('/api/account/usage?_t=' + Date.now());
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log('[TEST] Usage data received:', data);
return data.summary;
} catch (error) {
console.error('[TEST] Failed to fetch usage:', error);
showStatus(`Failed to fetch usage: ${error.message}`, 'error');
return null;
}
}
async function simulateTokenUsage() {
const tokens = parseInt(tokenAmountInput.value) || 1000;
simulateBtn.disabled = true;
simulateBtn.textContent = 'Simulating...';
try {
const response = await fetch('/api/test/simulate-tokens', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ tokens }),
});
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.log('[TEST] Simulation response:', data);
showStatus(`✓ Simulated ${tokens.toLocaleString()} tokens successfully`, 'success');
// Update display with returned summary
if (data.summary) {
updateUsageDisplay(data.summary);
}
} catch (error) {
console.error('[TEST] Failed to simulate:', error);
showStatus(`Failed to simulate: ${error.message}`, 'error');
} finally {
simulateBtn.disabled = false;
simulateBtn.textContent = 'Simulate Token Usage';
}
}
async function refreshUsage() {
refreshBtn.disabled = true;
refreshBtn.textContent = 'Refreshing...';
try {
const summary = await fetchUsage();
if (summary) {
updateUsageDisplay(summary);
showStatus('Usage data refreshed', 'success');
}
} catch (error) {
console.error('[TEST] Refresh failed:', error);
} finally {
refreshBtn.disabled = false;
refreshBtn.textContent = 'Refresh Usage';
}
}
// Event listeners
simulateBtn.addEventListener('click', simulateTokenUsage);
refreshBtn.addEventListener('click', refreshUsage);
// Load initial usage on page load
window.addEventListener('DOMContentLoaded', async () => {
console.log('[TEST] Page loaded, fetching initial usage...');
const summary = await fetchUsage();
if (summary) {
updateUsageDisplay(summary);
}
});
</script>
</body>
</html>