ai-zero-token 1.0.5 → 1.0.7
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/CHANGELOG.md +16 -0
- package/README.md +61 -4
- package/dist/cli/commands/help.js +4 -0
- package/dist/cli/commands/profiles.js +63 -0
- package/dist/cli/index.js +4 -0
- package/dist/core/providers/openai-codex/oauth.js +6 -3
- package/dist/core/services/auth-service.js +74 -0
- package/dist/core/services/image-service.js +10 -2
- package/dist/core/store/codex-auth-store.js +94 -0
- package/dist/core/store/profile-transfer.js +146 -0
- package/dist/server/admin-page.js +348 -10
- package/dist/server/app.js +256 -2
- package/docs/API_USAGE.md +19 -1
- package/package.json +2 -2
|
@@ -647,6 +647,19 @@ function renderAdminPage() {
|
|
|
647
647
|
min-width: 156px;
|
|
648
648
|
}
|
|
649
649
|
|
|
650
|
+
.account-selected-count {
|
|
651
|
+
min-height: 40px;
|
|
652
|
+
display: inline-flex;
|
|
653
|
+
align-items: center;
|
|
654
|
+
color: var(--text-muted);
|
|
655
|
+
font-size: 12px;
|
|
656
|
+
font-weight: 600;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
.account-modal-body .textarea {
|
|
660
|
+
min-height: 280px;
|
|
661
|
+
}
|
|
662
|
+
|
|
650
663
|
.account-grid {
|
|
651
664
|
display: grid;
|
|
652
665
|
grid-auto-rows: 1fr;
|
|
@@ -691,6 +704,30 @@ function renderAdminPage() {
|
|
|
691
704
|
display: grid;
|
|
692
705
|
gap: 6px;
|
|
693
706
|
min-width: 0;
|
|
707
|
+
flex: 1;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
.account-select {
|
|
711
|
+
display: inline-flex;
|
|
712
|
+
align-items: center;
|
|
713
|
+
gap: 6px;
|
|
714
|
+
min-height: 28px;
|
|
715
|
+
padding: 0 8px;
|
|
716
|
+
border: 1px solid var(--line);
|
|
717
|
+
border-radius: 8px;
|
|
718
|
+
background: #fff;
|
|
719
|
+
color: var(--text-muted);
|
|
720
|
+
font-size: 12px;
|
|
721
|
+
font-weight: 600;
|
|
722
|
+
cursor: pointer;
|
|
723
|
+
user-select: none;
|
|
724
|
+
white-space: nowrap;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
.account-select input {
|
|
728
|
+
width: 14px;
|
|
729
|
+
height: 14px;
|
|
730
|
+
margin: 0;
|
|
694
731
|
}
|
|
695
732
|
|
|
696
733
|
.account-name {
|
|
@@ -1365,7 +1402,7 @@ function renderAdminPage() {
|
|
|
1365
1402
|
<strong id="updatePanelTitle">\u53D1\u73B0\u65B0\u7248\u672C</strong>
|
|
1366
1403
|
<span id="updatePanelDetail"></span>
|
|
1367
1404
|
</div>
|
|
1368
|
-
<code class="update-command" id="updatePanelCommand">npm install -g ai-zero-token
|
|
1405
|
+
<code class="update-command" id="updatePanelCommand">npm install -g ai-zero-token</code>
|
|
1369
1406
|
</section>
|
|
1370
1407
|
|
|
1371
1408
|
<section class="summary-grid" id="summaryGrid"></section>
|
|
@@ -1380,6 +1417,7 @@ function renderAdminPage() {
|
|
|
1380
1417
|
</div>
|
|
1381
1418
|
<div class="actions">
|
|
1382
1419
|
<button class="btn-secondary" type="button" id="activateCurrentBtn">\u5B9A\u4F4D\u5F53\u524D\u8D26\u53F7</button>
|
|
1420
|
+
<button class="btn-secondary" type="button" id="exportSelectedProfilesBtn">\u5BFC\u51FA\u6240\u9009</button>
|
|
1383
1421
|
</div>
|
|
1384
1422
|
</div>
|
|
1385
1423
|
|
|
@@ -1398,8 +1436,8 @@ function renderAdminPage() {
|
|
|
1398
1436
|
<option value="expiry-asc">\u6309\u8FC7\u671F\u65F6\u95F4</option>
|
|
1399
1437
|
<option value="name-asc">\u6309\u90AE\u7BB1\u6392\u5E8F</option>
|
|
1400
1438
|
</select>
|
|
1439
|
+
<span class="account-selected-count" id="selectedProfileCount">\u5DF2\u9009\u62E9 0 \u4E2A</span>
|
|
1401
1440
|
</div>
|
|
1402
|
-
|
|
1403
1441
|
<div class="account-grid" id="profileList"></div>
|
|
1404
1442
|
</section>
|
|
1405
1443
|
|
|
@@ -1460,6 +1498,7 @@ function renderAdminPage() {
|
|
|
1460
1498
|
<div class="tester-tabs" id="testerTabs">
|
|
1461
1499
|
<button class="tab-btn is-active" type="button" data-endpoint="/v1/chat/completions">Chat</button>
|
|
1462
1500
|
<button class="tab-btn" type="button" data-endpoint="/v1/images/generations">Images</button>
|
|
1501
|
+
<button class="tab-btn" type="button" data-endpoint="/v1/images/edits">Edits</button>
|
|
1463
1502
|
<button class="tab-btn" type="button" data-endpoint="/v1/responses">Responses</button>
|
|
1464
1503
|
<button class="tab-btn" type="button" data-endpoint="/v1/models">Models</button>
|
|
1465
1504
|
</div>
|
|
@@ -1507,6 +1546,7 @@ function renderAdminPage() {
|
|
|
1507
1546
|
<button class="btn-secondary" type="button" data-example="/v1/responses">\u793A\u4F8B Responses</button>
|
|
1508
1547
|
<button class="btn-secondary" type="button" data-example="/v1/chat/completions">\u793A\u4F8B Chat</button>
|
|
1509
1548
|
<button class="btn-secondary" type="button" data-example="/v1/images/generations">\u793A\u4F8B Images</button>
|
|
1549
|
+
<button class="btn-secondary" type="button" data-example="/v1/images/edits">\u793A\u4F8B Edits</button>
|
|
1510
1550
|
<button class="btn-primary" id="runTestBtn" type="button">\u53D1\u9001\u8BF7\u6C42</button>
|
|
1511
1551
|
</div>
|
|
1512
1552
|
|
|
@@ -1578,6 +1618,41 @@ function renderAdminPage() {
|
|
|
1578
1618
|
</section>
|
|
1579
1619
|
</div>
|
|
1580
1620
|
|
|
1621
|
+
<div class="modal-backdrop" id="accountModal" aria-hidden="true">
|
|
1622
|
+
<section class="modal-card" role="dialog" aria-modal="true" aria-labelledby="accountModalTitle">
|
|
1623
|
+
<div class="modal-head">
|
|
1624
|
+
<div>
|
|
1625
|
+
<h3 id="accountModalTitle">\u65B0\u589E\u8D26\u53F7</h3>
|
|
1626
|
+
<p>\u9009\u62E9 OAuth \u767B\u5F55\uFF0C\u6216\u7C98\u8D34\u5355\u4E2A/\u6279\u91CF\u8D26\u53F7 JSON \u5BFC\u5165\u3002</p>
|
|
1627
|
+
</div>
|
|
1628
|
+
<div class="actions">
|
|
1629
|
+
<button class="btn-secondary" id="closeAccountModalBtn" type="button">\u5173\u95ED</button>
|
|
1630
|
+
</div>
|
|
1631
|
+
</div>
|
|
1632
|
+
<div class="modal-body account-modal-body">
|
|
1633
|
+
<div class="contact-notes">
|
|
1634
|
+
<div class="contact-note">
|
|
1635
|
+
<strong>\u767B\u5F55\u65B0\u589E</strong>
|
|
1636
|
+
<span>\u6253\u5F00 OpenAI OAuth \u6388\u6743\u6D41\u7A0B\uFF0C\u767B\u5F55\u6210\u529F\u540E\u81EA\u52A8\u4FDD\u5B58\u5E76\u5207\u6362\u4E3A\u5F53\u524D\u8D26\u53F7\u3002</span>
|
|
1637
|
+
<button class="btn-primary" id="oauthLoginBtn" type="button">\u767B\u5F55</button>
|
|
1638
|
+
</div>
|
|
1639
|
+
<div class="contact-note">
|
|
1640
|
+
<strong>\u6279\u91CF\u5BFC\u5165</strong>
|
|
1641
|
+
<span>\u652F\u6301\u5355\u4E2A\u5BF9\u8C61\u3001\u5BF9\u8C61\u6570\u7EC4\uFF0C\u6216\u5305\u542B profiles \u6570\u7EC4\u7684\u5BF9\u8C61\u3002\u5BFC\u5165\u540E\u6700\u540E\u4E00\u4E2A\u8D26\u53F7\u4F1A\u6210\u4E3A\u5F53\u524D\u8D26\u53F7\u3002</span>
|
|
1642
|
+
<div class="actions">
|
|
1643
|
+
<button class="btn-secondary" id="loadImportTemplateBtn" type="button">\u586B\u5165\u53C2\u8003\u683C\u5F0F</button>
|
|
1644
|
+
<button class="btn-primary" id="importProfileBtn" type="button">\u5BFC\u5165</button>
|
|
1645
|
+
</div>
|
|
1646
|
+
</div>
|
|
1647
|
+
</div>
|
|
1648
|
+
<div>
|
|
1649
|
+
<textarea class="textarea" id="profileImportJson" spellcheck="false" placeholder='\u7C98\u8D34\u8D26\u53F7 JSON\uFF0C\u652F\u6301 { "profiles": [...] } \u6279\u91CF\u5BFC\u5165'></textarea>
|
|
1650
|
+
<p class="hint">\u5BFC\u5165\u548C\u5BFC\u51FA\u7684 JSON \u90FD\u5305\u542B\u5B8C\u6574 access token \u548C refresh token\uFF0C\u8BF7\u53EA\u5728\u53EF\u4FE1\u73AF\u5883\u4E2D\u5904\u7406\u3002</p>
|
|
1651
|
+
</div>
|
|
1652
|
+
</div>
|
|
1653
|
+
</section>
|
|
1654
|
+
</div>
|
|
1655
|
+
|
|
1581
1656
|
<div class="modal-backdrop" id="contactModal" aria-hidden="true">
|
|
1582
1657
|
<section class="modal-card" role="dialog" aria-modal="true" aria-labelledby="contactModalTitle">
|
|
1583
1658
|
<div class="modal-head">
|
|
@@ -1622,6 +1697,7 @@ function renderAdminPage() {
|
|
|
1622
1697
|
status: "all",
|
|
1623
1698
|
sort: "quota-desc",
|
|
1624
1699
|
},
|
|
1700
|
+
selectedProfileIds: {},
|
|
1625
1701
|
testerResultTab: "response",
|
|
1626
1702
|
};
|
|
1627
1703
|
|
|
@@ -1646,6 +1722,11 @@ function renderAdminPage() {
|
|
|
1646
1722
|
tab: "Images",
|
|
1647
1723
|
description: "\u517C\u5BB9 OpenAI images.generations \u63A5\u53E3\u3002",
|
|
1648
1724
|
},
|
|
1725
|
+
"/v1/images/edits": {
|
|
1726
|
+
method: "POST",
|
|
1727
|
+
tab: "Edits",
|
|
1728
|
+
description: "\u517C\u5BB9 OpenAI images.edits JSON \u63A5\u53E3\u3002",
|
|
1729
|
+
},
|
|
1649
1730
|
};
|
|
1650
1731
|
|
|
1651
1732
|
const endpointSelect = document.getElementById("endpointSelect");
|
|
@@ -1659,6 +1740,7 @@ function renderAdminPage() {
|
|
|
1659
1740
|
const imageCapabilityHint = document.getElementById("imageCapabilityHint");
|
|
1660
1741
|
const runTestBtn = document.getElementById("runTestBtn");
|
|
1661
1742
|
const toggleEmailBtn = document.getElementById("toggleEmailBtn");
|
|
1743
|
+
const accountModal = document.getElementById("accountModal");
|
|
1662
1744
|
const contactModal = document.getElementById("contactModal");
|
|
1663
1745
|
const imagePreviewModal = document.getElementById("imagePreviewModal");
|
|
1664
1746
|
const contactBtn = document.getElementById("contactBtn");
|
|
@@ -1668,6 +1750,12 @@ function renderAdminPage() {
|
|
|
1668
1750
|
const profileSearch = document.getElementById("profileSearch");
|
|
1669
1751
|
const profileStatusFilter = document.getElementById("profileStatusFilter");
|
|
1670
1752
|
const profileSort = document.getElementById("profileSort");
|
|
1753
|
+
const profileImportJson = document.getElementById("profileImportJson");
|
|
1754
|
+
const importProfileBtn = document.getElementById("importProfileBtn");
|
|
1755
|
+
const oauthLoginBtn = document.getElementById("oauthLoginBtn");
|
|
1756
|
+
const loadImportTemplateBtn = document.getElementById("loadImportTemplateBtn");
|
|
1757
|
+
const exportSelectedProfilesBtn = document.getElementById("exportSelectedProfilesBtn");
|
|
1758
|
+
const selectedProfileCount = document.getElementById("selectedProfileCount");
|
|
1671
1759
|
const proxyEnabled = document.getElementById("proxyEnabled");
|
|
1672
1760
|
const proxyUrl = document.getElementById("proxyUrl");
|
|
1673
1761
|
const proxyNoProxy = document.getElementById("proxyNoProxy");
|
|
@@ -2244,6 +2332,21 @@ function renderAdminPage() {
|
|
|
2244
2332
|
});
|
|
2245
2333
|
}
|
|
2246
2334
|
|
|
2335
|
+
if (endpoint === "/v1/images/edits") {
|
|
2336
|
+
return formatJson({
|
|
2337
|
+
model: "gpt-image-2",
|
|
2338
|
+
prompt: "\u53C2\u8003\u8FD9\u5F20\u56FE\u7247\uFF0C\u751F\u6210\u4E00\u5F20\u66F4\u9002\u5408\u79D1\u6280\u4EA7\u54C1\u5E7F\u544A\u7684\u7248\u672C\uFF0C\u4FDD\u7559\u4E3B\u4F53\u6784\u56FE\uFF0C\u589E\u5F3A\u5149\u7EBF\u548C\u8D28\u611F\u3002",
|
|
2339
|
+
images: [
|
|
2340
|
+
{
|
|
2341
|
+
image_url: "data:image/png;base64,\u66FF\u6362\u4E3A\u4F60\u7684\u56FE\u7247base64",
|
|
2342
|
+
},
|
|
2343
|
+
],
|
|
2344
|
+
size: "1024x1024",
|
|
2345
|
+
quality: "low",
|
|
2346
|
+
response_format: "b64_json",
|
|
2347
|
+
});
|
|
2348
|
+
}
|
|
2349
|
+
|
|
2247
2350
|
return formatJson({
|
|
2248
2351
|
model: model,
|
|
2249
2352
|
input: "\u8BF7\u53EA\u56DE\u590D OK",
|
|
@@ -2255,6 +2358,10 @@ function renderAdminPage() {
|
|
|
2255
2358
|
const avg = requests.length
|
|
2256
2359
|
? requests.reduce(function (sum, item) { return sum + (item.durationMs || 0); }, 0) / requests.length
|
|
2257
2360
|
: 0;
|
|
2361
|
+
const codexAccountId = config.codex && config.codex.accountId ? config.codex.accountId : "";
|
|
2362
|
+
const codexProfile = codexAccountId && Array.isArray(config.profiles)
|
|
2363
|
+
? config.profiles.find(function (profile) { return profile.accountId === codexAccountId; })
|
|
2364
|
+
: null;
|
|
2258
2365
|
|
|
2259
2366
|
return [
|
|
2260
2367
|
{
|
|
@@ -2276,6 +2383,12 @@ function renderAdminPage() {
|
|
|
2276
2383
|
detail: "\u672A\u663E\u5F0F\u6307\u5B9A model \u65F6\u751F\u6548",
|
|
2277
2384
|
compact: true,
|
|
2278
2385
|
},
|
|
2386
|
+
{
|
|
2387
|
+
label: "Codex \u5F53\u524D\u8D26\u53F7",
|
|
2388
|
+
value: codexProfile ? getProfileDisplayLabel(codexProfile) : (codexAccountId ? maskIdentifier(codexAccountId) : "\u672A\u68C0\u6D4B\u5230"),
|
|
2389
|
+
detail: config.codex && config.codex.exists ? "\u6765\u81EA ~/.codex/auth.json" : "\u5C1A\u672A\u5E94\u7528\u5230 Codex",
|
|
2390
|
+
compact: true,
|
|
2391
|
+
},
|
|
2279
2392
|
{
|
|
2280
2393
|
label: "\u5F53\u524D\u7248\u672C",
|
|
2281
2394
|
value: getVersionValue(config),
|
|
@@ -2369,8 +2482,35 @@ function renderAdminPage() {
|
|
|
2369
2482
|
return filtered;
|
|
2370
2483
|
}
|
|
2371
2484
|
|
|
2485
|
+
function getSelectedProfileIds() {
|
|
2486
|
+
return Object.keys(state.selectedProfileIds).filter(function (profileId) {
|
|
2487
|
+
return !!state.selectedProfileIds[profileId];
|
|
2488
|
+
});
|
|
2489
|
+
}
|
|
2490
|
+
|
|
2491
|
+
function syncSelectedProfiles(config) {
|
|
2492
|
+
const profiles = Array.isArray(config.profiles) ? config.profiles : [];
|
|
2493
|
+
const availableIds = profiles.reduce(function (result, profile) {
|
|
2494
|
+
result[profile.profileId] = true;
|
|
2495
|
+
return result;
|
|
2496
|
+
}, {});
|
|
2497
|
+
getSelectedProfileIds().forEach(function (profileId) {
|
|
2498
|
+
if (!availableIds[profileId]) {
|
|
2499
|
+
delete state.selectedProfileIds[profileId];
|
|
2500
|
+
}
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
function updateSelectedProfileControls() {
|
|
2505
|
+
const count = getSelectedProfileIds().length;
|
|
2506
|
+
selectedProfileCount.textContent = "\u5DF2\u9009\u62E9 " + String(count) + " \u4E2A";
|
|
2507
|
+
exportSelectedProfilesBtn.disabled = count === 0;
|
|
2508
|
+
}
|
|
2509
|
+
|
|
2372
2510
|
function renderProfiles(config) {
|
|
2373
2511
|
const container = document.getElementById("profileList");
|
|
2512
|
+
syncSelectedProfiles(config);
|
|
2513
|
+
updateSelectedProfileControls();
|
|
2374
2514
|
const profiles = getFilteredProfiles(config);
|
|
2375
2515
|
const gridClass = profiles.length <= 0
|
|
2376
2516
|
? ""
|
|
@@ -2389,6 +2529,7 @@ function renderAdminPage() {
|
|
|
2389
2529
|
}
|
|
2390
2530
|
|
|
2391
2531
|
container.innerHTML = profiles.map(function (profile) {
|
|
2532
|
+
const selected = !!state.selectedProfileIds[profile.profileId];
|
|
2392
2533
|
const isSingleProfile = profiles.length === 1;
|
|
2393
2534
|
const health = getProfileHealth(profile);
|
|
2394
2535
|
const planType = getPlanType(profile);
|
|
@@ -2418,6 +2559,7 @@ function renderAdminPage() {
|
|
|
2418
2559
|
+ '<span class="badge ' + escapeHtml(imageCapability.badgeClass) + '">' + escapeHtml(imageCapability.label) + "</span>"
|
|
2419
2560
|
+ "</div>"
|
|
2420
2561
|
+ "</div>"
|
|
2562
|
+
+ '<label class="account-select"><input type="checkbox" data-profile-select data-profile-id="' + escapeHtml(profile.profileId) + '"' + (selected ? " checked" : "") + " /><span>\u9009\u62E9</span></label>"
|
|
2421
2563
|
+ "</div>"
|
|
2422
2564
|
+ '<div class="account-metrics">'
|
|
2423
2565
|
+ '<div class="quota-row">'
|
|
@@ -2440,6 +2582,8 @@ function renderAdminPage() {
|
|
|
2440
2582
|
+ "</div>"
|
|
2441
2583
|
+ '<div class="account-actions">'
|
|
2442
2584
|
+ actionButton
|
|
2585
|
+
+ '<button class="btn-secondary" type="button" data-profile-action="apply-codex" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5E94\u7528\u5230 Codex</button>'
|
|
2586
|
+
+ '<button class="btn-secondary" type="button" data-profile-action="export" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5BFC\u51FA</button>'
|
|
2443
2587
|
+ '<button class="btn-danger" type="button" data-profile-action="remove" data-profile-id="' + escapeHtml(profile.profileId) + '">\u5220\u9664</button>'
|
|
2444
2588
|
+ "</div>"
|
|
2445
2589
|
+ "</article>";
|
|
@@ -2450,13 +2594,15 @@ function renderAdminPage() {
|
|
|
2450
2594
|
const profiles = Array.isArray(config.profiles) ? config.profiles : [];
|
|
2451
2595
|
const now = Date.now();
|
|
2452
2596
|
const seeds = profiles.slice(0, 5).map(function (profile, index) {
|
|
2453
|
-
const endpoint = index %
|
|
2597
|
+
const endpoint = index % 5 === 0
|
|
2454
2598
|
? "/v1/chat/completions"
|
|
2455
|
-
: index %
|
|
2599
|
+
: index % 5 === 1
|
|
2456
2600
|
? "/v1/responses"
|
|
2457
|
-
: index %
|
|
2601
|
+
: index % 5 === 2
|
|
2458
2602
|
? "/v1/models"
|
|
2459
|
-
:
|
|
2603
|
+
: index % 5 === 3
|
|
2604
|
+
? "/v1/images/generations"
|
|
2605
|
+
: "/v1/images/edits";
|
|
2460
2606
|
const method = endpointMeta[endpoint].method;
|
|
2461
2607
|
return {
|
|
2462
2608
|
time: now - index * 15 * 60 * 1000,
|
|
@@ -2464,7 +2610,7 @@ function renderAdminPage() {
|
|
|
2464
2610
|
endpoint: endpoint,
|
|
2465
2611
|
accountEmail: profile.email || "",
|
|
2466
2612
|
accountFallback: profile.accountId || profile.profileId || "\u672A\u547D\u540D\u8D26\u53F7",
|
|
2467
|
-
model: endpoint
|
|
2613
|
+
model: endpoint.indexOf("/v1/images/") === 0 ? "gpt-image-2" : config.settings.defaultModel,
|
|
2468
2614
|
statusCode: 200,
|
|
2469
2615
|
durationMs: 860 + index * 230 + getPrimaryUsage(profile) * 8,
|
|
2470
2616
|
source: index % 2 === 0 ? "\u7BA1\u7406\u9875" : "CLI",
|
|
@@ -2695,7 +2841,7 @@ function renderAdminPage() {
|
|
|
2695
2841
|
|
|
2696
2842
|
function syncImageCapabilityHint(config) {
|
|
2697
2843
|
const capability = getImageCapability(config ? config.profile : null);
|
|
2698
|
-
const isImageEndpoint = endpointSelect.value === "/v1/images/generations";
|
|
2844
|
+
const isImageEndpoint = endpointSelect.value === "/v1/images/generations" || endpointSelect.value === "/v1/images/edits";
|
|
2699
2845
|
imageCapabilityHint.textContent = capability.detail;
|
|
2700
2846
|
imageCapabilityHint.className = capability.supported && !isImageEndpoint ? "hint" : "hint warn";
|
|
2701
2847
|
runTestBtn.disabled = isImageEndpoint && !capability.supported;
|
|
@@ -2832,7 +2978,7 @@ function renderAdminPage() {
|
|
|
2832
2978
|
}
|
|
2833
2979
|
|
|
2834
2980
|
async function login() {
|
|
2835
|
-
const button =
|
|
2981
|
+
const button = oauthLoginBtn;
|
|
2836
2982
|
setBusy(button, true);
|
|
2837
2983
|
authStatus.textContent = "\u6B63\u5728\u65B0\u589E\u8D26\u53F7\u3001\u7B49\u5F85 OAuth \u5B8C\u6210\uFF0C\u5E76\u540C\u6B65\u989D\u5EA6\u4FE1\u606F...";
|
|
2838
2984
|
try {
|
|
@@ -2845,6 +2991,7 @@ function renderAdminPage() {
|
|
|
2845
2991
|
if (config.profile && config.profile.quota) {
|
|
2846
2992
|
authStatus.textContent = "\u8D26\u53F7\u5DF2\u4FDD\u5B58\uFF0C\u5DF2\u5207\u6362\u4E3A\u5F53\u524D\u4F7F\u7528\u8D26\u53F7\u5E76\u540C\u6B65\u989D\u5EA6\u4FE1\u606F: " + getProfileDisplayLabel(config.profile);
|
|
2847
2993
|
}
|
|
2994
|
+
closeAccountModal();
|
|
2848
2995
|
} catch (error) {
|
|
2849
2996
|
authStatus.textContent = error.message;
|
|
2850
2997
|
} finally {
|
|
@@ -2871,6 +3018,15 @@ function renderAdminPage() {
|
|
|
2871
3018
|
}
|
|
2872
3019
|
|
|
2873
3020
|
async function runProfileAction(action, profileId, button) {
|
|
3021
|
+
if (action === "export") {
|
|
3022
|
+
await exportProfile(profileId, button);
|
|
3023
|
+
return;
|
|
3024
|
+
}
|
|
3025
|
+
if (action === "apply-codex") {
|
|
3026
|
+
await applyProfileToCodex(profileId, button);
|
|
3027
|
+
return;
|
|
3028
|
+
}
|
|
3029
|
+
|
|
2874
3030
|
setBusy(button, true);
|
|
2875
3031
|
authStatus.textContent = action === "activate" ? "\u6B63\u5728\u5207\u6362\u5F53\u524D\u8D26\u53F7..." : "\u6B63\u5728\u5220\u9664\u8D26\u53F7...";
|
|
2876
3032
|
try {
|
|
@@ -2903,6 +3059,141 @@ function renderAdminPage() {
|
|
|
2903
3059
|
}
|
|
2904
3060
|
}
|
|
2905
3061
|
|
|
3062
|
+
async function applyProfileToCodex(profileId, button) {
|
|
3063
|
+
setBusy(button, true);
|
|
3064
|
+
authStatus.textContent = "\u6B63\u5728\u5E94\u7528\u8D26\u53F7\u5230 Codex...";
|
|
3065
|
+
try {
|
|
3066
|
+
const result = await fetchJson("/_gateway/admin/codex/apply", {
|
|
3067
|
+
method: "POST",
|
|
3068
|
+
headers: {
|
|
3069
|
+
"Content-Type": "application/json",
|
|
3070
|
+
},
|
|
3071
|
+
body: formatJson({
|
|
3072
|
+
profileId: profileId,
|
|
3073
|
+
}),
|
|
3074
|
+
});
|
|
3075
|
+
const config = result.config || await fetchJson("/_gateway/admin/config");
|
|
3076
|
+
renderConfig(config);
|
|
3077
|
+
const codex = result.codex || config.codex || {};
|
|
3078
|
+
authStatus.textContent = "\u5DF2\u5E94\u7528\u5230 Codex\u3002\u65B0\u5F00\u7684 Codex \u4F1A\u8BDD\u5C06\u4F7F\u7528\u8BE5\u8D26\u53F7\u3002"
|
|
3079
|
+
+ (codex.backupPath ? " \u5DF2\u5907\u4EFD\u539F auth.json\u3002" : "");
|
|
3080
|
+
} catch (error) {
|
|
3081
|
+
authStatus.textContent = error.message;
|
|
3082
|
+
} finally {
|
|
3083
|
+
setBusy(button, false);
|
|
3084
|
+
}
|
|
3085
|
+
}
|
|
3086
|
+
|
|
3087
|
+
function downloadJsonFile(fileName, value) {
|
|
3088
|
+
const blob = new Blob([formatJson(value) + "\\n"], { type: "application/json" });
|
|
3089
|
+
const url = URL.createObjectURL(blob);
|
|
3090
|
+
const link = document.createElement("a");
|
|
3091
|
+
link.href = url;
|
|
3092
|
+
link.download = fileName;
|
|
3093
|
+
document.body.appendChild(link);
|
|
3094
|
+
link.click();
|
|
3095
|
+
link.remove();
|
|
3096
|
+
URL.revokeObjectURL(url);
|
|
3097
|
+
}
|
|
3098
|
+
|
|
3099
|
+
async function importProfile() {
|
|
3100
|
+
const raw = profileImportJson.value.trim();
|
|
3101
|
+
if (!raw) {
|
|
3102
|
+
authStatus.textContent = "\u8BF7\u5148\u7C98\u8D34\u8981\u5BFC\u5165\u7684\u8D26\u53F7 JSON\u3002";
|
|
3103
|
+
return;
|
|
3104
|
+
}
|
|
3105
|
+
|
|
3106
|
+
let payload;
|
|
3107
|
+
try {
|
|
3108
|
+
payload = JSON.parse(raw);
|
|
3109
|
+
} catch (_error) {
|
|
3110
|
+
authStatus.textContent = "\u5BFC\u5165\u5931\u8D25: JSON \u683C\u5F0F\u4E0D\u6B63\u786E\u3002";
|
|
3111
|
+
return;
|
|
3112
|
+
}
|
|
3113
|
+
|
|
3114
|
+
setBusy(importProfileBtn, true);
|
|
3115
|
+
authStatus.textContent = "\u6B63\u5728\u5BFC\u5165\u8D26\u53F7\u5E76\u540C\u6B65\u989D\u5EA6\u4FE1\u606F...";
|
|
3116
|
+
try {
|
|
3117
|
+
let config = await fetchJson("/_gateway/admin/profiles/import", {
|
|
3118
|
+
method: "POST",
|
|
3119
|
+
headers: {
|
|
3120
|
+
"Content-Type": "application/json",
|
|
3121
|
+
},
|
|
3122
|
+
body: formatJson({
|
|
3123
|
+
profile: payload,
|
|
3124
|
+
}),
|
|
3125
|
+
});
|
|
3126
|
+
renderConfig(config);
|
|
3127
|
+
const count = config.importedProfileCount || 1;
|
|
3128
|
+
const baseMessage = "\u5DF2\u5BFC\u5165 " + String(count) + " \u4E2A\u8D26\u53F7\uFF0C\u5E76\u5DF2\u5207\u6362\u4E3A\u5F53\u524D\u4F7F\u7528\u8D26\u53F7: " + getProfileDisplayLabel(config.profile);
|
|
3129
|
+
config = await syncQuotaAfterProfileChange(config, baseMessage);
|
|
3130
|
+
if (config.profile && config.profile.quota) {
|
|
3131
|
+
authStatus.textContent = "\u5DF2\u5BFC\u5165 " + String(count) + " \u4E2A\u8D26\u53F7\uFF0C\u989D\u5EA6\u4FE1\u606F\u5DF2\u540C\u6B65: " + getProfileDisplayLabel(config.profile);
|
|
3132
|
+
}
|
|
3133
|
+
profileImportJson.value = "";
|
|
3134
|
+
closeAccountModal();
|
|
3135
|
+
} catch (error) {
|
|
3136
|
+
authStatus.textContent = error.message;
|
|
3137
|
+
} finally {
|
|
3138
|
+
setBusy(importProfileBtn, false);
|
|
3139
|
+
}
|
|
3140
|
+
}
|
|
3141
|
+
|
|
3142
|
+
async function loadImportTemplate() {
|
|
3143
|
+
setBusy(loadImportTemplateBtn, true);
|
|
3144
|
+
authStatus.textContent = "\u6B63\u5728\u8BFB\u53D6\u5BFC\u5165\u53C2\u8003\u683C\u5F0F...";
|
|
3145
|
+
try {
|
|
3146
|
+
const result = await fetchJson("/_gateway/admin/profiles/import-template");
|
|
3147
|
+
profileImportJson.value = formatJson(result.profile);
|
|
3148
|
+
authStatus.textContent = "\u5DF2\u586B\u5165\u53C2\u8003\u683C\u5F0F\uFF0C\u53EF\u66FF\u6362\u5176\u4E2D\u7684 token \u540E\u5BFC\u5165\u3002";
|
|
3149
|
+
} catch (error) {
|
|
3150
|
+
authStatus.textContent = error.message;
|
|
3151
|
+
} finally {
|
|
3152
|
+
setBusy(loadImportTemplateBtn, false);
|
|
3153
|
+
}
|
|
3154
|
+
}
|
|
3155
|
+
|
|
3156
|
+
async function exportProfile(profileId, button, options) {
|
|
3157
|
+
setBusy(button, true);
|
|
3158
|
+
authStatus.textContent = "\u6B63\u5728\u5BFC\u51FA\u8D26\u53F7\u914D\u7F6E...";
|
|
3159
|
+
try {
|
|
3160
|
+
const exportAll = !!(options && options.all);
|
|
3161
|
+
const profileIds = options && Array.isArray(options.profileIds) ? options.profileIds : null;
|
|
3162
|
+
const result = await fetchJson("/_gateway/admin/profiles/export", {
|
|
3163
|
+
method: "POST",
|
|
3164
|
+
headers: {
|
|
3165
|
+
"Content-Type": "application/json",
|
|
3166
|
+
},
|
|
3167
|
+
body: formatJson(profileIds ? { profileIds: profileIds } : exportAll ? { all: true } : { profileId: profileId }),
|
|
3168
|
+
});
|
|
3169
|
+
const profile = result.profile;
|
|
3170
|
+
const isBundle = profile && Array.isArray(profile.profiles);
|
|
3171
|
+
const suffix = isBundle
|
|
3172
|
+
? "profiles-" + String(profile.profiles.length)
|
|
3173
|
+
: profile && profile.account_id ? profile.account_id : "active";
|
|
3174
|
+
downloadJsonFile("ai-zero-token-" + suffix + ".json", profile);
|
|
3175
|
+
authStatus.textContent = isBundle
|
|
3176
|
+
? "\u5DF2\u6279\u91CF\u5BFC\u51FA " + String(profile.profiles.length) + " \u4E2A\u8D26\u53F7\u3002\u8BF7\u59A5\u5584\u4FDD\u7BA1\u5BFC\u51FA\u7684 refresh token\u3002"
|
|
3177
|
+
: "\u8D26\u53F7\u914D\u7F6E\u5DF2\u5BFC\u51FA\u3002\u8BF7\u59A5\u5584\u4FDD\u7BA1\u5BFC\u51FA\u7684 refresh token\u3002";
|
|
3178
|
+
} catch (error) {
|
|
3179
|
+
authStatus.textContent = error.message;
|
|
3180
|
+
} finally {
|
|
3181
|
+
setBusy(button, false);
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
|
|
3185
|
+
async function exportSelectedProfiles() {
|
|
3186
|
+
const profileIds = getSelectedProfileIds();
|
|
3187
|
+
if (profileIds.length === 0) {
|
|
3188
|
+
authStatus.textContent = "\u8BF7\u5148\u52FE\u9009\u8981\u5BFC\u51FA\u7684\u8D26\u53F7\u3002";
|
|
3189
|
+
return;
|
|
3190
|
+
}
|
|
3191
|
+
|
|
3192
|
+
await exportProfile(null, exportSelectedProfilesBtn, {
|
|
3193
|
+
profileIds: profileIds,
|
|
3194
|
+
});
|
|
3195
|
+
}
|
|
3196
|
+
|
|
2906
3197
|
async function saveModel() {
|
|
2907
3198
|
const button = document.getElementById("saveModelBtn");
|
|
2908
3199
|
const select = document.getElementById("defaultModel");
|
|
@@ -3081,6 +3372,16 @@ function renderAdminPage() {
|
|
|
3081
3372
|
}
|
|
3082
3373
|
}
|
|
3083
3374
|
|
|
3375
|
+
function openAccountModal() {
|
|
3376
|
+
accountModal.classList.add("is-open");
|
|
3377
|
+
accountModal.setAttribute("aria-hidden", "false");
|
|
3378
|
+
}
|
|
3379
|
+
|
|
3380
|
+
function closeAccountModal() {
|
|
3381
|
+
accountModal.classList.remove("is-open");
|
|
3382
|
+
accountModal.setAttribute("aria-hidden", "true");
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3084
3385
|
function openContactModal() {
|
|
3085
3386
|
contactModal.classList.add("is-open");
|
|
3086
3387
|
contactModal.setAttribute("aria-hidden", "false");
|
|
@@ -3091,7 +3392,7 @@ function renderAdminPage() {
|
|
|
3091
3392
|
contactModal.setAttribute("aria-hidden", "true");
|
|
3092
3393
|
}
|
|
3093
3394
|
|
|
3094
|
-
document.getElementById("loginBtn").addEventListener("click",
|
|
3395
|
+
document.getElementById("loginBtn").addEventListener("click", openAccountModal);
|
|
3095
3396
|
document.getElementById("refreshBtn").addEventListener("click", function () {
|
|
3096
3397
|
authStatus.textContent = "\u6B63\u5728\u540C\u6B65\u989D\u5EA6\u4E0E\u7248\u672C\u72B6\u6001...";
|
|
3097
3398
|
refreshConfig({
|
|
@@ -3103,6 +3404,11 @@ function renderAdminPage() {
|
|
|
3103
3404
|
});
|
|
3104
3405
|
});
|
|
3105
3406
|
document.getElementById("logoutBtn").addEventListener("click", logout);
|
|
3407
|
+
oauthLoginBtn.addEventListener("click", login);
|
|
3408
|
+
importProfileBtn.addEventListener("click", importProfile);
|
|
3409
|
+
loadImportTemplateBtn.addEventListener("click", loadImportTemplate);
|
|
3410
|
+
exportSelectedProfilesBtn.addEventListener("click", exportSelectedProfiles);
|
|
3411
|
+
document.getElementById("closeAccountModalBtn").addEventListener("click", closeAccountModal);
|
|
3106
3412
|
contactBtn.addEventListener("click", openContactModal);
|
|
3107
3413
|
document.getElementById("closeContactBtn").addEventListener("click", closeContactModal);
|
|
3108
3414
|
document.getElementById("closeImagePreviewBtn").addEventListener("click", closeImagePreviewModal);
|
|
@@ -3124,6 +3430,10 @@ function renderAdminPage() {
|
|
|
3124
3430
|
});
|
|
3125
3431
|
|
|
3126
3432
|
document.getElementById("profileList").addEventListener("click", function (event) {
|
|
3433
|
+
if (event.target.closest("[data-profile-select]")) {
|
|
3434
|
+
return;
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3127
3437
|
const button = event.target.closest("[data-profile-action]");
|
|
3128
3438
|
if (!button) {
|
|
3129
3439
|
return;
|
|
@@ -3138,6 +3448,25 @@ function renderAdminPage() {
|
|
|
3138
3448
|
runProfileAction(action, profileId, button);
|
|
3139
3449
|
});
|
|
3140
3450
|
|
|
3451
|
+
document.getElementById("profileList").addEventListener("change", function (event) {
|
|
3452
|
+
const checkbox = event.target.closest("[data-profile-select]");
|
|
3453
|
+
if (!checkbox) {
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
|
|
3457
|
+
const profileId = checkbox.getAttribute("data-profile-id");
|
|
3458
|
+
if (!profileId) {
|
|
3459
|
+
return;
|
|
3460
|
+
}
|
|
3461
|
+
|
|
3462
|
+
if (checkbox.checked) {
|
|
3463
|
+
state.selectedProfileIds[profileId] = true;
|
|
3464
|
+
} else {
|
|
3465
|
+
delete state.selectedProfileIds[profileId];
|
|
3466
|
+
}
|
|
3467
|
+
updateSelectedProfileControls();
|
|
3468
|
+
});
|
|
3469
|
+
|
|
3141
3470
|
document.getElementById("activateCurrentBtn").addEventListener("click", function () {
|
|
3142
3471
|
if (!state.config || !state.config.profile || !state.config.profile.profileId) {
|
|
3143
3472
|
return;
|
|
@@ -3209,6 +3538,12 @@ function renderAdminPage() {
|
|
|
3209
3538
|
}
|
|
3210
3539
|
});
|
|
3211
3540
|
|
|
3541
|
+
accountModal.addEventListener("click", function (event) {
|
|
3542
|
+
if (event.target === accountModal) {
|
|
3543
|
+
closeAccountModal();
|
|
3544
|
+
}
|
|
3545
|
+
});
|
|
3546
|
+
|
|
3212
3547
|
imagePreviewModal.addEventListener("click", function (event) {
|
|
3213
3548
|
if (event.target === imagePreviewModal) {
|
|
3214
3549
|
closeImagePreviewModal();
|
|
@@ -3222,6 +3557,9 @@ function renderAdminPage() {
|
|
|
3222
3557
|
if (event.key === "Escape" && contactModal.classList.contains("is-open")) {
|
|
3223
3558
|
closeContactModal();
|
|
3224
3559
|
}
|
|
3560
|
+
if (event.key === "Escape" && accountModal.classList.contains("is-open")) {
|
|
3561
|
+
closeAccountModal();
|
|
3562
|
+
}
|
|
3225
3563
|
});
|
|
3226
3564
|
|
|
3227
3565
|
setTesterResultTab(state.testerResultTab);
|