kingkont 0.7.38 → 0.7.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.html +29 -29
- package/package.json +1 -1
- package/server.js +50 -1
package/index.html
CHANGED
|
@@ -1037,10 +1037,7 @@
|
|
|
1037
1037
|
<div class="sidebar-list" id="episodeList"></div>
|
|
1038
1038
|
</div>
|
|
1039
1039
|
<div class="sidebar-footer">
|
|
1040
|
-
<
|
|
1041
|
-
<span class="dot"></span>
|
|
1042
|
-
<span id="balanceValue">— credits</span>
|
|
1043
|
-
</span>
|
|
1040
|
+
<div id="balancesAll" style="display:flex; flex-direction:column; gap:4px;"></div>
|
|
1044
1041
|
<span id="jobsInfo" class="jobs-info" style="display:none;"></span>
|
|
1045
1042
|
<span class="hint">Перетаскивай файлы на холст · @имя для ссылок</span>
|
|
1046
1043
|
</div>
|
|
@@ -2116,32 +2113,35 @@ window.addEventListener('DOMContentLoaded', async () => {
|
|
|
2116
2113
|
// red (≤0). Также экспортирована глобально как window.refreshBalance —
|
|
2117
2114
|
// чтобы settings-окно могло триггерить обновление после login/logout.
|
|
2118
2115
|
async function refreshBalance() {
|
|
2119
|
-
const
|
|
2120
|
-
|
|
2121
|
-
|
|
2116
|
+
const wrap = document.getElementById('balancesAll');
|
|
2117
|
+
if (!wrap) return;
|
|
2118
|
+
let data = {};
|
|
2122
2119
|
try {
|
|
2123
|
-
const
|
|
2124
|
-
if (
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
const d =
|
|
2136
|
-
|
|
2137
|
-
pill
|
|
2138
|
-
pill.
|
|
2139
|
-
pill.
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
pill.
|
|
2143
|
-
|
|
2144
|
-
|
|
2120
|
+
const r = await fetch('/api/balance/all');
|
|
2121
|
+
if (r.ok) data = await r.json();
|
|
2122
|
+
} catch {}
|
|
2123
|
+
wrap.innerHTML = '';
|
|
2124
|
+
// Один pill на провайдер. Если у провайдера нет данных (выключен или
|
|
2125
|
+
// API не дал баланс) — pill не рендерим.
|
|
2126
|
+
const pills = [
|
|
2127
|
+
{ key: 'kingkont', label: 'KingKont', onClick: () => window.openTxLog?.(), low: 100, fmt: (a) => `<b>${a.toLocaleString('ru-RU')}</b> credits` },
|
|
2128
|
+
{ key: 'openrouter', label: 'OpenRouter', low: 0.5, fmt: (a) => `<b>$${a.toFixed(2)}</b>` },
|
|
2129
|
+
{ key: 'elevenlabs', label: 'ElevenLabs', low: 1000, fmt: (a) => `<b>${a.toLocaleString('ru-RU')}</b> chars` },
|
|
2130
|
+
];
|
|
2131
|
+
for (const p of pills) {
|
|
2132
|
+
const d = data[p.key];
|
|
2133
|
+
if (!d || typeof d.amount !== 'number') continue;
|
|
2134
|
+
const pill = document.createElement('span');
|
|
2135
|
+
pill.className = 'balance-info';
|
|
2136
|
+
pill.title = `Баланс ${p.label}` + (p.onClick ? ' · клик — лог списаний' : '');
|
|
2137
|
+
if (d.amount > 0 && d.amount < (p.low || 0)) pill.classList.add('low');
|
|
2138
|
+
if (d.amount <= 0) pill.classList.add('empty');
|
|
2139
|
+
pill.innerHTML = `<span class="dot"></span><span style="color:#888;font-size:10px;margin-right:4px;">${p.label}</span><span>${p.fmt(d.amount)}</span>`;
|
|
2140
|
+
if (p.onClick) {
|
|
2141
|
+
pill.style.cursor = 'pointer';
|
|
2142
|
+
pill.addEventListener('click', p.onClick);
|
|
2143
|
+
}
|
|
2144
|
+
wrap.appendChild(pill);
|
|
2145
2145
|
}
|
|
2146
2146
|
}
|
|
2147
2147
|
window.refreshBalance = refreshBalance;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "kingkont",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.39",
|
|
4
4
|
"description": "KingKont \u00b7 Chatium \u2014 \u043d\u043e\u0434-\u0440\u0435\u0434\u0430\u043a\u0442\u043e\u0440 \u0441\u0446\u0435\u043d \u0441 AI-\u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 (\u043a\u0430\u0440\u0442\u0438\u043d\u043a\u0438/\u0432\u0438\u0434\u0435\u043e/\u0433\u043e\u043b\u043e\u0441/SFX/\u043c\u0443\u0437\u044b\u043a\u0430/\u0442\u0435\u043a\u0441\u0442)",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"bin": {
|
package/server.js
CHANGED
|
@@ -657,7 +657,7 @@ async function handleTransactions(req, res) {
|
|
|
657
657
|
}
|
|
658
658
|
}
|
|
659
659
|
|
|
660
|
-
// ---------- /api/balance (
|
|
660
|
+
// ---------- /api/balance (KingKont — legacy single-balance endpoint) ----------
|
|
661
661
|
async function handleBalance(req, res) {
|
|
662
662
|
const s = getSettings();
|
|
663
663
|
if (!s.useChatium || !s.chatium?.token || !s.chatium?.base) {
|
|
@@ -682,6 +682,54 @@ async function handleBalance(req, res) {
|
|
|
682
682
|
}
|
|
683
683
|
}
|
|
684
684
|
|
|
685
|
+
// ---------- /api/balance/all (агрегированные балансы всех включённых провайдеров) ----------
|
|
686
|
+
async function handleBalanceAll(req, res) {
|
|
687
|
+
const s = getSettings();
|
|
688
|
+
const out = {};
|
|
689
|
+
// KingKont — credits.
|
|
690
|
+
if (s.useChatium && s.chatium?.token && s.chatium?.base) {
|
|
691
|
+
try {
|
|
692
|
+
const url = s.chatium.base.replace(/\/$/, '') + CHATIUM_PATHS.balance;
|
|
693
|
+
const r = await fetch(url, { headers: { 'Authorization': `Bearer ${s.chatium.token}` } });
|
|
694
|
+
const d = await r.json().catch(() => ({}));
|
|
695
|
+
if (r.ok && typeof d.balance === 'number') out.kingkont = { unit: 'credits', amount: d.balance };
|
|
696
|
+
} catch {}
|
|
697
|
+
}
|
|
698
|
+
// ElevenLabs — characters_left = limit - used.
|
|
699
|
+
if (s.useElevenlabs && process.env.ELEVENLABS_API_KEY) {
|
|
700
|
+
try {
|
|
701
|
+
const r = await fetch(`${ELEVEN_BASE}/v1/user/subscription`, {
|
|
702
|
+
headers: { 'xi-api-key': process.env.ELEVENLABS_API_KEY },
|
|
703
|
+
});
|
|
704
|
+
const d = await r.json().catch(() => ({}));
|
|
705
|
+
if (r.ok && typeof d.character_count === 'number' && typeof d.character_limit === 'number') {
|
|
706
|
+
out.elevenlabs = {
|
|
707
|
+
unit: 'chars',
|
|
708
|
+
amount: Math.max(0, d.character_limit - d.character_count),
|
|
709
|
+
limit: d.character_limit,
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
} catch {}
|
|
713
|
+
}
|
|
714
|
+
// OpenRouter — credits в USD.
|
|
715
|
+
if (s.useOpenrouter && process.env.OPENROUTER_API_KEY) {
|
|
716
|
+
try {
|
|
717
|
+
const r = await fetch('https://openrouter.ai/api/v1/credits', {
|
|
718
|
+
headers: { 'Authorization': `Bearer ${process.env.OPENROUTER_API_KEY}` },
|
|
719
|
+
});
|
|
720
|
+
const d = await r.json().catch(() => ({}));
|
|
721
|
+
if (r.ok && d.data && typeof d.data.total_credits === 'number') {
|
|
722
|
+
out.openrouter = {
|
|
723
|
+
unit: 'usd',
|
|
724
|
+
amount: Math.max(0, (d.data.total_credits || 0) - (d.data.total_usage || 0)),
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
} catch {}
|
|
728
|
+
}
|
|
729
|
+
// KIE — нет публичного balance-endpoint в их API; пропускаем.
|
|
730
|
+
send(res, 200, out);
|
|
731
|
+
}
|
|
732
|
+
|
|
685
733
|
// ---------- /api/sfx (Chatium ИЛИ ElevenLabs Sound Effects) ----------
|
|
686
734
|
async function handleSfx(req, res) {
|
|
687
735
|
const { text, durationSeconds, promptInfluence = 0.3 } = await readJson(req);
|
|
@@ -885,6 +933,7 @@ const server = createServer(async (req, res) => {
|
|
|
885
933
|
if (req.method === 'POST' && url.pathname === '/api/music') return handleMusic(req, res);
|
|
886
934
|
if (req.method === 'POST' && url.pathname === '/api/text') return handleText(req, res);
|
|
887
935
|
if (req.method === 'GET' && url.pathname === '/api/balance') return handleBalance(req, res);
|
|
936
|
+
if (req.method === 'GET' && url.pathname === '/api/balance/all') return handleBalanceAll(req, res);
|
|
888
937
|
if (req.method === 'GET' && url.pathname === '/api/transactions') return handleTransactions(req, res);
|
|
889
938
|
if (req.method === 'GET') return serveStatic(res, url);
|
|
890
939
|
send(res, 404, 'not found');
|