Update creditTracker.js

This commit is contained in:
Antique3e
2025-10-29 01:27:10 +05:30
committed by GitHub
parent 3d8dc1fc32
commit 55e9971d28
+52 -113
View File
@@ -1,21 +1,6 @@
/**
* ComfyUI Credit Tracker - ENHANCED VERSION
* Tracks Modal GPU + CPU + Memory credits with animated color bar
*
* ✅ CHANGES FROM ORIGINAL:
* 1. Added CPU/Memory cost properties to constructor
* 2. Added detectCompute() method (NEW)
* 3. Modified detectGPU() to store separate costs
* 4. Added detectCompute() call in init()
* 5. Enhanced showDetails() with cost breakdown
*
* ⚠️ PRESERVED (NOT CHANGED):
* - setInterval timing (1000ms)
* - Save frequency (every 10 seconds)
* - saveBalance() method
* - updateDisplay() method
* - Color bar animation
* - balance.json format
* ComfyUI Credit Tracker
* Simple UI extension to track Modal GPU credits with animated color bar
*/
import { app } from "../../scripts/app.js";
@@ -24,42 +9,32 @@ import { api } from "../../scripts/api.js";
// ========================================
// COLOR CONFIGURATION (CRYSTOOLS STYLE - ONLY 2 COLORS)
// ========================================
// Change these values to customize the bar colors
const COLORS = {
BACKGROUND: '#222222', // Dark gray background (when no credits)
START: '#236692', // Green - Full credits (100%)
END: '#EB3B5A', // Red - No credits (0%)
TEXT: '#ffffff' // White text on top of bar
};
// ========================================
//🆕 Modal Pricing Constants
const MODAL_PRICING = {
CPU_PER_CORE_HOUR: 0.0473, // $0.0473 per vCPU core per hour
MEMORY_PER_GB_HOUR: 0.0080 // $0.0080 per GB per hour
BACKGROUND: '#222222',
START: '#236692',
END: '#EB3B5A',
TEXT: '#ffffff'
};
// ========================================
class CreditTracker {
constructor() {
// ===== EXISTING PROPERTIES (UNCHANGED) =====
this.config = null;
this.balance = null;
this.gpuType = null;
this.gpuCount = 1;
this.costPerSecond = 0;
this.costPerSecond = 0; // CHANGED: Now includes GPU + CPU + Memory
this.lastUpdate = Date.now();
this.displayElement = null;
this.sliderElement = null; // The animated color bar
this.containerElement = null; // The main container
this.sliderElement = null;
this.containerElement = null;
// 🆕 NEW PROPERTIES - CPU & Memory tracking
// NEW: Store CPU and Memory info for display
this.cpuCores = 0;
this.memoryGB = 0;
this.gpuCostPerHour = 0;
this.cpuCostPerHour = 0;
this.memoryCostPerHour = 0;
// =========================================
this.init();
}
@@ -67,8 +42,7 @@ class CreditTracker {
async init() {
await this.loadConfig();
await this.loadBalance();
await this.detectGPU();
await this.detectCompute(); // 🆕 NEW: Detect CPU & Memory
await this.detectGPU(); // CHANGED: Now also detects CPU and Memory
this.createDisplay();
this.startTracking();
}
@@ -89,7 +63,9 @@ class CreditTracker {
"NVIDIA A10G": 1.10,
"Tesla T4": 0.59
},
gpu_count: 1
gpu_count: 1,
cpu_cost_per_core_per_hour: 0.04,
memory_cost_per_gb_per_hour: 0.008
};
console.log('⚠️ Credit Tracker: Using default config');
}
@@ -125,64 +101,45 @@ class CreditTracker {
try {
const response = await api.fetchApi('/credit_tracker/gpu_info');
if (response.ok) {
const gpuInfo = await response.json();
this.gpuType = gpuInfo.gpu_name;
const info = await response.json();
// GPU detection (existing logic)
this.gpuType = info.gpu_name;
this.gpuCount = this.config.gpu_count;
let costPerHour = 1.0;
let gpuCostPerHour = 1.0;
for (const [gpuName, cost] of Object.entries(this.config.gpu_costs_per_hour)) {
if (this.gpuType.includes(gpuName) || gpuName.includes(this.gpuType)) {
costPerHour = cost;
gpuCostPerHour = cost;
break;
}
}
this.gpuCostPerHour = gpuCostPerHour * this.gpuCount;
// 🆕 CHANGED: Store GPU cost separately (was: this.costPerSecond = ...)
this.gpuCostPerHour = costPerHour;
console.log(`✅ GPU: ${this.gpuType} @ $${costPerHour.toFixed(4)}/hr`);
// NEW: CPU and Memory detection (same approach as GPU)
this.cpuCores = info.cpu_cores || 0;
this.memoryGB = info.memory_total_gb || 0;
this.cpuCostPerHour = this.config.cpu_cost_per_core_per_hour * this.cpuCores;
this.memoryCostPerHour = this.config.memory_cost_per_gb_per_hour * this.memoryGB;
// CHANGED: Total cost per second = GPU + CPU + Memory
const totalCostPerHour = this.gpuCostPerHour + this.cpuCostPerHour + this.memoryCostPerHour;
this.costPerSecond = totalCostPerHour / 3600;
console.log(`✅ Credit Tracker: GPU detected - ${this.gpuType} @ $${this.gpuCostPerHour.toFixed(2)}/hr`);
console.log(`✅ Credit Tracker: CPU detected - ${this.cpuCores} cores @ $${this.cpuCostPerHour.toFixed(4)}/hr`);
console.log(`✅ Credit Tracker: Memory detected - ${this.memoryGB.toFixed(2)} GB @ $${this.memoryCostPerHour.toFixed(4)}/hr`);
console.log(`✅ Credit Tracker: Total cost - $${totalCostPerHour.toFixed(4)}/hr`);
}
} catch (error) {
console.error('❌ Credit Tracker: GPU detection failed', error);
console.error('❌ Credit Tracker: Detection failed', error);
this.gpuType = "Unknown";
this.gpuCostPerHour = 1.0;
this.costPerSecond = (1.0 / 3600) * this.gpuCount;
}
}
// 🆕 NEW METHOD: Detect CPU & Memory (similar to detectGPU)
async detectCompute() {
try {
const response = await api.fetchApi('/credit_tracker/compute_resources');
if (response.ok) {
const computeInfo = await response.json();
this.cpuCores = computeInfo.cpu_cores;
this.memoryGB = computeInfo.memory_gb;
// Calculate costs using Modal pricing
this.cpuCostPerHour = this.cpuCores * MODAL_PRICING.CPU_PER_CORE_HOUR;
this.memoryCostPerHour = this.memoryGB * MODAL_PRICING.MEMORY_PER_GB_HOUR;
console.log(`✅ CPU: ${this.cpuCores} vCPU @ $${this.cpuCostPerHour.toFixed(4)}/hr`);
console.log(`✅ Memory: ${this.memoryGB} GB @ $${this.memoryCostPerHour.toFixed(4)}/hr`);
}
} catch (error) {
console.error('❌ Compute detection failed, using defaults', error);
// Fallback to reasonable defaults
this.cpuCores = 12;
this.memoryGB = 32.0;
this.cpuCostPerHour = 12 * MODAL_PRICING.CPU_PER_CORE_HOUR;
this.memoryCostPerHour = 32.0 * MODAL_PRICING.MEMORY_PER_GB_HOUR;
}
// 🆕 Calculate total cost per second (GPU + CPU + Memory)
const totalCostPerHour = (this.gpuCostPerHour + this.cpuCostPerHour + this.memoryCostPerHour) * this.gpuCount;
this.costPerSecond = totalCostPerHour / 3600;
console.log(`💰 Total: $${totalCostPerHour.toFixed(4)}/hr = $${(this.costPerSecond * 3600).toFixed(6)}/sec`);
}
// ===== createDisplay() - UNCHANGED FROM ORIGINAL =====
createDisplay() {
// Main container - dark background visible when bar shrinks
const container = document.createElement('div');
container.id = 'credit-tracker-display';
container.style.cssText = `
@@ -202,7 +159,6 @@ class CreditTracker {
padding: 4px 10px;
`;
// Progress bar slider (the animated color bar)
const slider = document.createElement('div');
slider.id = 'credit-tracker-slider';
slider.style.cssText = `
@@ -217,7 +173,6 @@ class CreditTracker {
`;
container.appendChild(slider);
// Text label (displays $XX.XX on top of the bar)
this.displayElement = document.createElement('div');
this.displayElement.style.cssText = `
position: relative;
@@ -230,14 +185,11 @@ class CreditTracker {
`;
container.appendChild(this.displayElement);
// Store references
this.sliderElement = slider;
this.containerElement = container;
// Click to show details
container.onclick = () => this.showDetails();
// Hover effect
container.onmouseenter = () => {
container.style.opacity = '0.8';
};
@@ -247,7 +199,6 @@ class CreditTracker {
this.updateDisplay();
// Add to header bar
const addToHeader = () => {
const menuBar = document.querySelector('.comfyui-menu') ||
document.querySelector('.comfy-menu');
@@ -263,7 +214,7 @@ class CreditTracker {
console.log('✅ Credit Tracker: Display added before Manager');
} else {
menuBar.appendChild(container);
console.log('✅ Credit Tracker: Display added to header (Manager not found)');
console.log('✅ Credit Tracker: Display added to header');
}
} else {
console.warn('⚠️ Credit Tracker: Menu bar not found, retrying...');
@@ -278,41 +229,32 @@ class CreditTracker {
}
}
// ===== updateDisplay() - UNCHANGED FROM ORIGINAL =====
updateDisplay() {
if (this.displayElement && this.sliderElement) {
const balance = this.balance.remaining_balance;
const percentage = (balance / this.config.starting_balance) * 100;
// Update text display
this.displayElement.textContent = `$${balance.toFixed(2)}`;
// Update bar width (shrinks from 100% to 0% as credits decrease)
this.sliderElement.style.width = `${percentage}%`;
// Color transition (green to red)
const redAmount = 100 - percentage;
this.sliderElement.style.backgroundColor =
`color-mix(in srgb, ${COLORS.END} ${redAmount}%, ${COLORS.START})`;
}
}
// ===== startTracking() - UNCHANGED FROM ORIGINAL =====
startTracking() {
// Update credits every second
// NO CHANGES: Same tracking logic, just uses updated costPerSecond
setInterval(() => {
const now = Date.now();
const elapsed = (now - this.lastUpdate) / 1000;
// Deduct credits based on total cost (GPU + CPU + Memory)
const cost = this.costPerSecond * elapsed;
this.balance.remaining_balance = Math.max(0, this.balance.remaining_balance - cost);
this.balance.last_updated = new Date().toISOString();
// Update the display
this.updateDisplay();
// Save to file every 10 seconds
if (Math.floor(now / 1000) % 10 === 0) {
this.saveBalance();
}
@@ -321,7 +263,6 @@ class CreditTracker {
}, 1000);
}
// ===== saveBalance() - UNCHANGED FROM ORIGINAL =====
async saveBalance() {
try {
await api.fetchApi('/credit_tracker/balance', {
@@ -334,35 +275,34 @@ class CreditTracker {
}
}
// 🆕 ENHANCED: showDetails() with cost breakdown
showDetails() {
const balance = this.balance.remaining_balance;
const startingBalance = this.config.starting_balance;
const used = startingBalance - balance;
const percentage = ((balance / startingBalance) * 100).toFixed(1);
const totalCostPerHour = this.costPerSecond * 3600;
const totalCostPerHour = this.gpuCostPerHour + this.cpuCostPerHour + this.memoryCostPerHour;
const hoursRemaining = balance > 0 ? (balance / totalCostPerHour).toFixed(2) : '0.00';
// CHANGED: Updated to show GPU, CPU, Memory breakdown
const message = `
💰 Credit Tracker Details
━━━━━━━━━━━━━━━━━━━━━━━━
💵 Remaining: $${balance.toFixed(2)}
📊 Used: $${used.toFixed(2)}
💳 Starting: $${startingBalance.toFixed(2)}
🔋 Percentage: ${percentage}%
📋 Percentage: ${percentage}%
🎮 GPU: ${this.gpuType}
🔢 GPU Count: ${this.gpuCount}
💲 GPU Cost: $${this.gpuCostPerHour.toFixed(4)}/hour
Count: ${this.gpuCount}
Cost: $${this.gpuCostPerHour.toFixed(4)}/hour
💻 CPU: ${this.cpuCores} vCPU cores
💲 CPU Cost: $${this.cpuCostPerHour.toFixed(4)}/hour
🖥️ CPU: ${this.cpuCores} cores
Cost: $${this.cpuCostPerHour.toFixed(4)}/hour
🧠 Memory: ${this.memoryGB.toFixed(2)} GB
💲 Memory Cost: $${this.memoryCostPerHour.toFixed(4)}/hour
💾 Memory: ${this.memoryGB.toFixed(2)} GB
Cost: $${this.memoryCostPerHour.toFixed(4)}/hour
━━━━━━━━━━━━━━━━━━━━━━━━
💰 TOTAL: $${totalCostPerHour.toFixed(4)}/hour
💲 Total Cost: $${totalCostPerHour.toFixed(4)}/hour
⏱️ Time Remaining: ${hoursRemaining} hours
`.trim();
@@ -370,11 +310,10 @@ class CreditTracker {
}
}
// Register the extension with ComfyUI
app.registerExtension({
name: "comfyui.credit.tracker.enhanced",
name: "comfyui.credit.tracker",
async setup() {
new CreditTracker();
console.log('✅ Credit Tracker Enhanced: Extension loaded (with CPU+Memory tracking)');
console.log('✅ Credit Tracker: Extension loaded');
}
});