diff --git a/.env b/.env
new file mode 100644
index 0000000..a23ad42
--- /dev/null
+++ b/.env
@@ -0,0 +1,18 @@
+PORT=3000
+
+# Database Configuration
+DB_USER=postgres
+DB_HOST=postgres
+DB_NAME=tokenwatch
+DB_PASSWORD=your_db_password
+DB_PORT=5432
+
+# ntfy Configuration
+NTFY_URL=https://ntfy.orfel.de/Token-Watch
+ALERT_THRESHOLD_PERCENT=80
+
+# Provider API Keys
+ANTIGRAVITY_API_KEY=your_antigravity_key
+ANTIGRAVITY_ENDPOINT=https://api.antigravity.google/v1/quota
+POE_API_KEY=sk-poe-4V66fvDHHGp8nx4ig2Mz5608HdTY0hk-AN-DiAV2axY
+MINIMAX_API_KEY=sk-api-y831YokKIsrn8f8oo19ilogA1kzZJAEfKrRslw8wowvOfevxAAj7t8TZWH3G4rin4DxUIMfQRejs5y7jAnEB2i3r1zBp0z4aPU6w_kD8MEZqWYDlcHsHB9o
diff --git a/public/app.js b/public/app.js
index 016c20b..50766aa 100644
--- a/public/app.js
+++ b/public/app.js
@@ -37,8 +37,6 @@ function updateCard(providerId, quota) {
// Set color gradient position based on percentage
fill.style.backgroundPosition = `${100 - percentage}% 0`;
- statusText.innerText = `${percentage.toFixed(1)}% Used (${quota.used} / ${quota.total})`;
-
// Meme reactions based on percentage
if (percentage > 90) {
meme.style.transform = 'scale(1.2) rotate(5deg)';
@@ -47,6 +45,16 @@ function updateCard(providerId, quota) {
statusText.style.color = 'var(--success)';
}
+ if (quota.provider.toLowerCase() === 'minimax' && quota.meta) {
+ const reset5h = new Date(quota.meta.intervalReset).toLocaleTimeString();
+ const resetWeekly = new Date(quota.meta.weeklyReset).toLocaleDateString();
+ statusText.innerHTML = `5h Limit: ${quota.meta.intervalUsed}% (Resets: ${reset5h})
Weekly: ${quota.meta.weeklyUsed}% (Resets: ${resetWeekly})`;
+ } else if (quota.provider.toLowerCase() === 'poe') {
+ statusText.innerText = `${percentage.toFixed(1)}% Used (${(quota.used).toLocaleString()} / ${(quota.total).toLocaleString()})`;
+ } else {
+ statusText.innerText = `${percentage.toFixed(1)}% Used (${quota.used} / ${quota.total})`;
+ }
+
if (percentage >= 100) {
confetti({
particleCount: 100,
diff --git a/src/server.ts b/src/server.ts
index 525244b..1f3abbc 100644
--- a/src/server.ts
+++ b/src/server.ts
@@ -1,6 +1,7 @@
import express from 'express';
import path from 'path';
-import { getLatestQuotas, getQuotaHistory } from './services/db';
+import { getQuotaHistory } from './services/db';
+import { fetchAllQuotas } from './services/providers';
import './cron'; // Start the cron jobs
const app = express();
@@ -11,7 +12,7 @@ app.use(express.json());
app.get('/api/quotas', async (req, res) => {
try {
- const quotas = await getLatestQuotas();
+ const quotas = await fetchAllQuotas();
res.json(quotas);
} catch (error) {
console.error('Error fetching quotas:', error);
diff --git a/src/services/db.ts b/src/services/db.ts
index c0cdf62..cddca21 100644
--- a/src/services/db.ts
+++ b/src/services/db.ts
@@ -18,6 +18,7 @@ export interface QuotaEntry {
total: number;
percentage: number;
timestamp?: Date;
+ meta?: any;
}
export async function initDb() {
diff --git a/src/services/providers.ts b/src/services/providers.ts
index c1d4321..f43be36 100644
--- a/src/services/providers.ts
+++ b/src/services/providers.ts
@@ -28,24 +28,21 @@ export async function fetchAntigravityQuota(): Promise {
export async function fetchPoeQuota(): Promise {
try {
- // According to docs, returns available point balance
const res = await axios.get('https://api.poe.com/usage/current_balance', {
headers: {
'Authorization': `Bearer ${process.env.POE_API_KEY}`
}
});
- // POE logic: 75000 daily points is standard. We might need to adjust based on actual API payload.
- // Assuming response has: { available: number }
const available = res.data.current_point_balance || 0;
- const total = 2575000;
+ const total = 2500000;
const used = total - available > 0 ? total - available : 0;
const percentage = (used / total) * 100;
return { provider: 'POE', used, total, percentage };
} catch (error: any) {
console.error('Error fetching POE quota:', error.message);
- return { provider: 'POE', used: 0, total: 75000, percentage: 0 };
+ return { provider: 'POE', used: 0, total: 2500000, percentage: 0 };
}
}
@@ -58,11 +55,22 @@ export async function fetchMinimaxQuota(): Promise {
});
const remains = res.data.model_remains?.find((r: any) => r.model_name === 'general');
- const total = 100;
- const percentage = remains ? (100 - remains.current_weekly_remaining_percent) : 0;
+ const intervalUsed = remains ? (100 - remains.current_interval_remaining_percent) : 0;
+ const weeklyUsed = remains ? (100 - remains.current_weekly_remaining_percent) : 0;
+
+ // Use the highest percentage for the progress bar logic
+ const percentage = Math.max(intervalUsed, weeklyUsed);
const used = percentage;
+ const total = 100;
+
+ const meta = {
+ intervalUsed,
+ weeklyUsed,
+ intervalReset: remains ? remains.end_time : null,
+ weeklyReset: remains ? remains.weekly_end_time : null
+ };
- return { provider: 'MiniMax', used, total, percentage };
+ return { provider: 'MiniMax', used, total, percentage, meta };
} catch (error: any) {
console.error('Error fetching MiniMax quota:', error.message);
return { provider: 'MiniMax', used: 0, total: 100, percentage: 0 };