Compare commits

..

82 Commits
1.0.8 ... mdui2

Author SHA1 Message Date
wood chen
55c266975c
Update README.md 2025-07-12 06:54:16 +08:00
wood chen
e5efcbd3f3
Update README.md 2025-06-26 18:08:25 +08:00
wood chen
e17d22f6d7
Update index.html 2025-06-26 16:02:58 +08:00
wood chen
10473ef9b5
Update README.md 2025-06-26 15:55:00 +08:00
65218d4d78 Merge branch 'mdui2' of https://github.com/woodchen-ink/openai-billing-query into mdui2 2024-10-31 07:54:46 +08:00
b512ae25de style(index.html, static/css.css): Update API URL options and background image 2024-10-31 07:54:43 +08:00
wood chen
31f05dbda1
Update README.md 2024-08-05 20:46:45 +08:00
wood chen
75a66371f0
Update README.md 2024-08-05 20:45:53 +08:00
wood chen
896fe279cd
Update README.md 2024-04-15 20:49:12 +08:00
wood chen
1bdc566c45
Update README.md 2024-01-30 04:45:55 +08:00
wood chen
63ff54c29d
Update README.md 2024-01-04 17:57:01 +08:00
wood chen
12885d66a1
Merge pull request #37 from mouxangithub/mdui2
将刷新接口合并成一个域名请求,潘多拉自带platform的api,无需单独再配
2024-01-04 11:17:55 +08:00
Johnathan Abts
82af4c8351 fix: 修改 2024-01-04 11:11:07 +08:00
Johnathan Abts
063e12e55a fix: 将刷新接口合并成一个域名请求,潘多拉自带platform的api,无需单独再配 2024-01-04 11:09:24 +08:00
wood chen
4c65ee7a71 删除错误提交 2024-01-03 22:56:14 +08:00
wood chen
853855d819
Merge pull request #36 from mouxangithub/mdui2
fix: 新增刷新sess功能
2024-01-03 22:27:26 +08:00
Johnathan Abts
c93807a2f7 fix: 新增刷新sess功能 2024-01-03 17:07:53 +08:00
d63b02957a 修改自定义链接框描述 2023-12-31 16:16:43 +08:00
0eb792da0a 完善查询界面和复制功能
添加 Axios 以实现更稳健的 HTTP 请求。 标准化错误处理和
单元格溢出行为。 启用将所有敏感 ID 复制到剪贴板。
限制 API url 修剪。 调整复制按钮的样式。

这些更改提高了查询界面的可靠性和美观性。
axios 替代了之前 HTTP 请求的 Fetch API 来处理错误
更加优雅。 单元格内容被截断并带有工具提示以保持
布局。 新的复制按钮让用户可以轻松收集所有敏感 ID。
细微的样式调整也增强了可用性。

总体而言,查询组件现在更具弹性且用户友好。
2023-12-29 21:35:14 +08:00
Johnathan Abts
01be618870 Merge branch 'mdui2' of https://github.com/mouxangithub/openai-billing-query into mdui2 2023-12-29 14:31:48 +08:00
Johnathan Abts
94fe780b48 fix: 移除woff2文件转成base64 2023-12-29 14:31:44 +08:00
Johnathan Abts
598ee4864c
Create jekyll-gh-pages.yml 2023-12-29 14:27:09 +08:00
Johnathan Abts
8878b8fdc3 1 2023-12-29 14:26:15 +08:00
Johnathan Abts
befd543d57
Create static.yml 2023-12-29 14:24:59 +08:00
Johnathan Abts
2e90adc476 fix: 添加通过PandoraNext获取sess 2023-12-29 13:41:50 +08:00
6df15c2796 update 2023-12-15 09:53:57 +08:00
4cfdee7ca5 bug 2023-12-15 09:27:50 +08:00
wood chen
09c40f92a5
Update README.md
新增示意图
2023-12-15 00:43:01 +08:00
wood chen
9c70af453a
Merge pull request #33 from woodchen-ink:woodchen-ink/issue32
修复,并改用mdui2
2023-12-15 00:39:16 +08:00
da6381d71f 请问通过access token获取sess]失效了么
Fixes #32
2023-12-15 00:38:28 +08:00
aecc0946d0 更新依赖包,修改颜色 2023-12-14 04:00:49 +08:00
e184b1e3a9 修复变量定义 2023-11-09 04:08:02 +08:00
72c754a825 1 2023-11-05 18:55:25 +08:00
wood chen
5770c3f939
Update README.md 2023-10-27 03:52:15 -05:00
81c6c76bb5 update 2023-10-25 18:49:37 +08:00
5334b69624 update 2023-10-25 18:49:22 +08:00
8449465349 update 2023-10-25 18:43:51 +08:00
80619cb480 update 2023-10-24 13:13:55 +08:00
wood chen
b6e65dc65a
Update README.md 2023-10-22 16:16:35 +08:00
7c931a6d31 update 2023-10-21 15:41:59 +08:00
e3abc00e1b update 2023-10-21 15:37:33 +08:00
918213a64e update 2023-10-21 14:50:08 +08:00
08b6a4186b update 2023-10-21 13:05:18 +08:00
ce51f6ffca update 2023-10-21 02:41:25 +08:00
a478392113 update 2023-10-21 02:25:56 +08:00
68725fa6cc mdui2 2023-10-21 01:36:37 +08:00
387fd638f8 Merge branch 'main' of https://github.com/woodchen-ink/openai-billing-query 2023-10-20 20:18:58 +08:00
596978d35f update 2023-10-20 20:17:00 +08:00
wood chen
352f3fd129
Update README.md 2023-10-19 00:38:12 -05:00
wood chen
2513055b20
Update README.md 2023-10-17 04:59:46 -05:00
e0c7bbe9bc udpate 2023-10-13 12:47:39 +08:00
wood chen
c90b571749
Update README.md 2023-10-12 23:15:32 -05:00
407f53647b update 2023-09-04 14:14:38 +08:00
wood chen
6ccf8048f3
Merge pull request #29 from woodchen-ink:woodchen-ink/issue28
查中转渠道余额显示错误
2023-09-04 13:25:22 +08:00
2608b14b81 查中转渠道余额显示错误
Fixes #28
2023-09-04 13:25:08 +08:00
wood chen
99a615d707
Merge pull request #27 from woodchen-ink:woodchen-ink/issue26
调整下右侧表格的颜色,顺便加一下每一列的线
2023-09-03 21:34:14 +08:00
dbc489523f 调整下右侧表格的颜色,顺便加一下每一列的线
Fixes #26
2023-09-03 21:33:44 +08:00
c6bfa059d0 表头加个说明 2023-09-03 20:23:17 +08:00
wood chen
d418a7be85
Merge pull request #25 from woodchen-ink/woodchen-ink/issue24 2023-09-03 20:12:27 +08:00
5eebcc886f 为了支持单行多信息匹配,结果发现只输入sess或者key的时候查不到了
Fixes #24
2023-09-03 20:11:50 +08:00
a0e750ee56 改为cdnjs公共源 2023-09-03 20:02:50 +08:00
wood chen
bb4057a058
Merge pull request #23 from woodchen-ink/woodchen-ink/issue22 2023-09-01 22:35:45 +08:00
f1a5f4f01f 一行内容里有多个信息时,sess不会识别
Fixes #22
2023-09-01 22:34:00 +08:00
45630a63e1 update 2023-09-01 22:05:27 +08:00
wood chen
497eaa45b1
Merge pull request #21 from woodchen-ink/woodchen-ink/issue20 2023-09-01 21:18:12 +08:00
b720564fdc 修复布局
Fixes #20
2023-09-01 21:17:36 +08:00
f33a1e538d 输入框改成8行 2023-09-01 19:28:27 +08:00
wood chen
4a7edfc05a
Merge pull request #19 from woodchen-ink:woodchen-ink/issue18
修复预付费额度账号的总额度显示问题
2023-09-01 17:17:36 +08:00
c35af318d0 修复预付费额度账号的总额度显示问题
Fixes #18
2023-09-01 17:17:21 +08:00
44b11534a7 速率一列拉宽了点 2023-09-01 16:48:07 +08:00
cc1dcc6fe3 添加获取sess链接,优化下页面列表显示 2023-09-01 16:43:31 +08:00
wood chen
975c558a3d
Merge pull request #17 from woodchen-ink:woodchen-ink/issue16
改为使用tailwind css和daisyUI进行布局,绑卡信息和组织信息改为可选显示。
2023-09-01 16:37:29 +08:00
c1d8d1dc3e 改为使用tailwind css和daisyUI进行布局,绑卡信息和组织信息改为可选显示。
Fixes #16
2023-09-01 16:36:19 +08:00
wood chen
712c500681
Merge pull request #15 from woodchen-ink:woodchen-ink/issue14
通过access token 获取sess
2023-08-30 21:47:28 +08:00
232b613aee update 2023-08-30 21:47:02 +08:00
7f936e54e4 update 2023-08-30 21:44:55 +08:00
d1059d3b6e update 2023-08-30 21:42:28 +08:00
1aa9aeebca 通过access token 获取sess
Fixes #14
2023-08-30 21:38:37 +08:00
0db7de1f51 Merge branch 'main' of https://github.com/woodchen-ink/openai-billing-query 2023-08-30 20:30:48 +08:00
d8a50578bc update 2023-08-30 18:39:56 +08:00
d339ef59f7 加了个广告 2023-08-30 12:15:36 +08:00
99472ac3fd update 2023-08-29 21:22:55 +08:00
15 changed files with 1854 additions and 324 deletions

51
.github/workflows/jekyll-gh-pages.yml vendored Normal file
View File

@ -0,0 +1,51 @@
# Sample workflow for building and deploying a Jekyll site to GitHub Pages
name: Deploy Jekyll with GitHub Pages dependencies preinstalled
on:
# Runs on pushes targeting the default branch
push:
branches: ["mdui2"]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
# Build job
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v4
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
# Deployment job
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View File

@ -3,19 +3,25 @@
star,please. star,please.
## [English](README_EN.md) [![Use EdgeOne Pages to deploy](https://cdnstatic.tencentcs.com/edgeone/pages/deploy.svg)](https://edgeone.ai/pages/new?repository-url=https%3A%2F%2Fgithub.com%2Fwoodchen-ink%2Fopenai-billing-query)
Telegram交流群https://t.me/ai_cn2023
## 在线访问(使用Cloudflare Pages部署)
新版本https://openai-billing-query.czl.net/
daisyUI版本https://daisyui.o-b.pages.dev/
## [English](README_EN.md)
## 最新示意图(2023.08.28) ## 最新示意图(2023.08.28)
![1693240108324.png](https://cdn-img.czl.net/2023/08/29/64eccb2da01a1.png) ![screenshot-20231215-003431](https://github.com/woodchen-ink/openai-billing-query/assets/95951386/076cbeff-7b93-45a8-bf36-303a1dc711f0)
![1693240132856.png](https://cdn-img.czl.net/2023/08/29/64eccb46017e7.png)
![screenshot-20231215-003509](https://github.com/woodchen-ink/openai-billing-query/assets/95951386/e5da95ec-544e-4541-944e-308cf8ffe0e6)
## SESS ID获取方法 ## SESS ID获取方法
请见我的个人博客提供视频教程https://woodchen.ink/1266.html [请见我的个人博客,提供视频教程](https://woodchen.ink/archives/how-to-query-the-balance-of-openai-in-batches-expires-gpt4-whether-to-tie-cards-1ov1aw)
## 支持自定义反代接口 ## 支持自定义反代接口
在第361行添加自己的接口代码 在第361行添加自己的接口代码
@ -27,6 +33,7 @@ Telegram交流群https://t.me/ai_cn2023
## 怎么部署 ## 怎么部署
下载index.html直接打开就行除了背景图片没有任何外部资源。 下载index.html直接打开就行除了背景图片没有任何外部资源。
## 贡献列表 ## 贡献列表
| 人员 | 贡献内容 | | 人员 | 贡献内容 |
@ -34,9 +41,16 @@ Telegram交流群https://t.me/ai_cn2023
| [qiyue](https://github.com/qiyue-rgb) | 技术协助 | | [qiyue](https://github.com/qiyue-rgb) | 技术协助 |
| 🙊 | cloudflare反代地址 | | 🙊 | cloudflare反代地址 |
## CDN acceleration and security protection for this project are sponsored by Tencent EdgeOne.
[Best Asian CDN, Edge, and Secure Solutions - Tencent EdgeOne](https://edgeone.ai/?from=github)
[![image](https://github.com/user-attachments/assets/3375c4c0-8cd4-4675-ab88-220b6bc4f23b)](https://edgeone.ai/?from=github)
## 广告 ## 广告
- [CZL Chat](https://chat.czl.net)稳定商业版AI服务。 - [CZL Chat](https://chat.czl.net)稳定商业版AI服务。
- [CZLOapi](https://oapi.czl.net)OPENAI代理服务无需翻墙。 - [CZLOapi](https://oapi.czl.net)OPENAI代理服务无需翻墙。
- 个人博客https://woodchen.ink - 个人博客https://woodchen.ink
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=woodchen-ink/openai-billing-query&type=Date)](https://api.star-history.com/svg?repos=woodchen-ink/openai-billing-query&type=Date)

107
get_sess.html Normal file
View File

@ -0,0 +1,107 @@
<!DOCTYPE html>
<html class="mdui-theme-light" lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>通过access_token来获取sess</title>
<meta name="description" content="批量快速查询OPENAI的余额支持可视化展现已用比例、额度、已用量、未用量、是否GPT-4、是否GPT4-32K、是否绑卡、绑卡信息、组织信息、是否有效">
<link rel="stylesheet" href="./static/css-1.css" type="text/css" />
<link rel="stylesheet" href="./static/mdui/mdui.css">
<script src="./static/mdui/mdui.global.js"></script>
<script>mdui.setColorScheme('#0d2d44');</script>
</head>
<body>
<mdui-layout>
<mdui-layout-main>
<div class="mdui-main-container">
<h2>查询结果</h2>
<div class="mdui-table">
<table id="result-table">
<thead>
<tr>
<th>序号</th>
<th>Access_Token</th>
<th>user id</th>
<th>email</th>
<th>name</th>
<th>phone number</th>
<th>注册时间</th>
<th>sess id</th>
<th>sess id生成时间</th>
<th>org id</th>
<th>IP Country</th>
</tr>
</thead>
<tbody>
<!-- 表格内容 -->
</tbody>
</table>
</div>
</div>
</mdui-layout-main>
<mdui-top-app-bar>
<mdui-button-icon icon="menu" close-on-overlay-click id="toggle-button"
style="color: white;"></mdui-button-icon>
<mdui-top-app-bar-title
style="text-align: center;color:white;">通过access_token来获取sess</mdui-top-app-bar-title>
</mdui-top-app-bar>
<mdui-navigation-drawer open class="left-drawer" close-on-overlay-click>
<div class="left-drawer-main">
<h3>输入 API KEY</h3>
<p>本站不保存 KEY 信息,查询后请自行保存</p>
<mdui-text-field id="api-key-input" placeholder="请输入access_token多个请换行" label="access_token"
rows="6"></mdui-text-field>
<mdui-select id="api-url-select" icon="airline_stops" label="查询线路" value="https://api.openai.com"
onchange="toggleCustomUrlInput()">
<mdui-menu-item value="https://api.openai.com">[官网线路]api.openai.com</mdui-menu-item>
<mdui-menu-item value="https://oapi.czl.net">[CZLoapi线路]oapi.czl.net</mdui-menu-item>
<mdui-menu-item value="https://openai.996.lat">[群友CF反代]openai.996.lat</mdui-menu-item>
<mdui-menu-item value="https://gateway.ai.cloudflare.com/v1/feedd0aa8abd6875052d86a94f1baf83/test/openai">CF Gateway</mdui-menu-item>
<mdui-menu-item value="custom">[已前置https]自定义</mdui-menu-item>
</mdui-select>
<mdui-text-field type="text" id="custom-url-input" placeholder="输入自定义API填域名即可无需https://"
class="hidden"></mdui-text-field>
<div style="height:2rem"></div>
<mdui-button full-width id="query-button" icon="search" onclick="sendRequest()">
查询
</mdui-button>
<!-- 下半部分 -->
<h4>页面列表</h4>
<mdui-menu style="width:100%;margin-top:20px;">
<mdui-menu-item icon="search" href="index.html">查API信息</mdui-menu-item>
<mdui-menu-item icon="vpn_key" href="get_sess.html">通过access token获取sess</mdui-menu-item>
<mdui-menu-item icon="vpn_key" href="get_sess2.html">通过PandoraNext获取sess</mdui-menu-item>
<mdui-menu-item icon="vpn_key" href="refresh_see.html">刷新Platform相关信息刷新sess</mdui-menu-item>
<mdui-menu-item icon="build" href="https://woodchen.ink/1266.html"
target="_blank">手动获取sess的方法</mdui-menu-item>
</mdui-menu>
<div style="margin-top:20px;">
<mdui-chip elevated icon="code"> 本网页由<a href="https://woodchen.ink"
target="_blank">woodchen</a>开源于<a
href="https://github.com/woodchen-ink/openai-billing-query" target="_blank">Github</a>
</mdui-chip>
</div>
</div>
</mdui-navigation-drawer>
</mdui-layout>
<script src="./static/getsess.js"></script>
</body>
</html>

158
get_sess2.html Normal file
View File

@ -0,0 +1,158 @@
<!DOCTYPE html>
<html class="mdui-theme-light" lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>通过PandoraNext来获取Sensitive Id</title>
<meta
name="description"
content="批量快速查询OPENAI的余额支持可视化展现已用比例、额度、已用量、未用量、是否GPT-4、是否GPT4-32K、是否绑卡、绑卡信息、组织信息、是否有效"
/>
<link rel="stylesheet" href="./static/css-1.css" type="text/css" />
<link rel="stylesheet" href="./static/mdui/mdui.css" />
<script src="./static/mdui/mdui.global.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.6.3/axios.min.js"
integrity="sha512-JWQFV6OCC2o2x8x46YrEeFEQtzoNV++r9im8O8stv91YwHNykzIS2TbvAlFdeH0GVlpnyd79W0ZGmffcRi++Bw=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
<script>
mdui.setColorScheme("#0d2d44");
</script>
</head>
<body>
<style>
th,
td {
cursor: pointer; /* 添加鼠标指针样式 */
white-space: normal; /* 设置为normal使内容自动换行 */
word-wrap: break-word; /* 设置为break-word以确保长单词/链接被截断换行 */
max-width: 300px;
}
/* 复制按钮样式 */
.copy-button {
height: 36px;
cursor: pointer;
background-color: #4caf50;
color: white;
padding: 8px;
border: none;
border-radius: 4px;
margin: 8px 0;
margin-top: 20px;
margin-left: 20px;
}
</style>
<mdui-layout>
<mdui-layout-main>
<div class="mdui-main-container">
<div style="display: flex">
<h2 style="flex: 1">查询结果</h2>
<button class="copy-button" onclick="copySess()">复制sess</button>
<button class="copy-button" onclick="copyTable()">
复制全部内容
</button>
</div>
<div class="mdui-table">
<table id="result-table">
<thead>
<tr>
<th>序号</th>
<th>邮箱账户</th>
<th>手机号</th>
<th>Sensitive ID</th>
<th>Refresh Token</th>
<th>Access Token</th>
<th>Sensitive ID创建时间</th>
</tr>
</thead>
<tbody id="result-tbody" style="max-width: 100%">
<!-- 表格内容 -->
</tbody>
</table>
</div>
</div>
</mdui-layout-main>
<mdui-top-app-bar>
<mdui-button-icon
icon="menu"
close-on-overlay-click
id="toggle-button"
style="color: white"
></mdui-button-icon>
<mdui-top-app-bar-title style="text-align: center; color: white"
>通过PandoraNext来获取Sensitive Id</mdui-top-app-bar-title
>
</mdui-top-app-bar>
<mdui-navigation-drawer open class="left-drawer" close-on-overlay-click>
<div class="left-drawer-main">
<h3>输入 API KEY</h3>
<p>本站不保存 KEY 信息,查询后请自行保存</p>
<mdui-text-field
id="api-key-input"
placeholder="请输入账号密码,格式为'账号|密码|MFA验证码',多个请换行"
label="username|password|MFA"
rows="6"
></mdui-text-field>
<mdui-text-field
type="text"
id="custom-url-input"
placeholder="输入PandoraNext的API地址和前缀"
></mdui-text-field>
<div style="height: 2rem"></div>
<mdui-button
full-width
id="query-button"
icon="search"
onclick="sendRequest()"
>
查询
</mdui-button>
<!-- 下半部分 -->
<h4>页面列表</h4>
<mdui-menu style="width: 100%; margin-top: 20px">
<mdui-menu-item icon="search" href="index.html"
>查API信息</mdui-menu-item
>
<mdui-menu-item icon="vpn_key" href="get_sess.html"
>通过access token获取sess</mdui-menu-item
>
<mdui-menu-item icon="vpn_key" href="get_sess2.html"
>通过PandoraNext获取sess</mdui-menu-item
>
<mdui-menu-item icon="vpn_key" href="refresh_see.html"
>刷新Platform相关信息刷新sess</mdui-menu-item
>
<mdui-menu-item
icon="build"
href="https://woodchen.ink/1266.html"
target="_blank"
>手动获取Sensitive Id的方法</mdui-menu-item
>
</mdui-menu>
<div style="margin-top: 20px">
<mdui-chip elevated icon="code">
本网页由<a href="https://woodchen.ink" target="_blank">woodchen</a
>开源于<a
href="https://github.com/woodchen-ink/openai-billing-query"
target="_blank"
>Github</a
>
</mdui-chip>
</div>
</div>
</mdui-navigation-drawer>
</mdui-layout>
<script src="./static/getsess2.js"></script>
</body>
</html>

View File

@ -1,94 +1,112 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html class="mdui-theme-light" lang="zh-cmn-Hans">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>OpenAI API 信息查询</title> <title>OpenAI API 信息查询</title>
<meta name="description" content="批量快速查询OPENAI的余额支持可视化展现已用比例、额度、已用量、未用量、是否GPT-4、是否GPT4-32K、是否绑卡、绑卡信息、组织信息、是否有效"> <meta name="description" content="批量快速查询OPENAI的余额支持可视化展现已用比例、额度、已用量、未用量、是否GPT-4、是否GPT4-32K、是否绑卡、绑卡信息、组织信息、是否有效">
<link rel="stylesheet" href="static/css.css" type="text/css" /> <link rel="stylesheet" href="./static/css-1.css" type="text/css" />
<link rel="stylesheet" href="./static/mdui/mdui.css">
<script src="./static/mdui/mdui.global.js"></script>
<script>mdui.setColorScheme('#0d2d44');</script>
</head> </head>
<body> <body>
<header> <mdui-layout>
<h1 class="text-3xl font-semibold text-center mb-8 text-gradient">OpenAI API 信息查询</h1> <mdui-layout-main>
<p class=" text-center text-gradient" style="text-align: center;">7月22日更新后需使用sess码进行查询。使用key只能查询总额度、绑卡、GPT4和组织ID。 <div class="mdui-main-container">
</p> <h2>查询结果</h2>
</a> <div class="mdui-table">
</header> <table id="result-table">
<div class="query">
<div>
<h2 style="display: inline-block;">输入 API KEY</h2>
<p style="display: inline-block; font-size: smaller;">本站不保存 KEY 信息,查询后请自行保存</p>
</div>
<textarea id="api-key-input" placeholder="请输入 API-KEY或sessID多个可直接粘贴"></textarea></p>
<!-- API链接选择框 -->
<div class="api-url-container"></div>
<!-- API链接选择 -->
<div>
<h2 style="display: inline-block;">选择查询线路</h2>
<p style="display: inline-block; font-size: smaller;">支持自定义线路,官网线路需要魔法</p>
</div>
<select id="api-url-select" style="width:49%;">
<option value="https://api.openai.com">【官网线路】api.openai.com</option>
<option value="https://oapi.czl.net">【CZLoapi线路】oapi.czl.net</option>
<option value="https://openai.996.lat">【群友提供公益CF反代,勿测重要key】openai.996.lat</option>
<option value="custom">【已前置https】自定义 ...</option>
</select>
<!-- 自定义API链接输入框 -->
<input type="text" id="custom-url-input" placeholder="输入自定义API填域名即可无需https://" style="width:45%;" />
</div>
<button :class="{ loading }" :disabled="loading" onclick="sendRequest()">查询</button> </p>
</div>
<h2 id="result-head" style="visibility:hidden">查询结果</h2>
<table id="result-table" style="visibility:hidden">
<thead> <thead>
<tr> <tr>
<th style="width:35px">序号</th> <th>序号</th>
<th>API KEY</th> <th>API KEY</th>
<th style="width: 50px;">总额度</th> <th>总额度</th>
<th style="width: 50px">已使用</th> <th>已使用</th>
<th style="width: 50px">剩余量</th> <th>剩余量</th>
<th style="width: 90px">已用比例</th> <th id="progressbar-header">已用比例</th>
<th style="width: 90px">到期时间</th> <th>到期时间</th>
<th style="width: 50px">GPT-3.5</th> <th>模型[最高]</th>
<th style="width: 50px">GPT-4</th> <th>绑卡</th>
<th style="width: 50px">32K</th> <th id="subinfo-header">绑卡信息</th>
<th style="width: 60px">绑卡</th> <th id="setid-header">组织信息</th>
<th style="width: 120px">绑卡信息</th> <th>速率[RPM,TPM-RPD]</th>
<th style="width: 120px">组织信息</th> <th>有效</th>
<th style="width: 120px">速率</th>
<th style="width: 50px;">是否有效</th>
</tr> </tr>
</thead> </thead>
<tbody></tbody> <tbody>
<!-- 表格内容 -->
</tbody>
</table> </table>
<div id="myModal" class="modal"> </div>
<div class="modal-content"> </div>
<div class="modal-header"> </mdui-layout-main>
<h2>详细信息</h2>
<span class="close">&times;</span>
<mdui-top-app-bar>
<mdui-button-icon icon="menu" close-on-overlay-click id="toggle-button" style="color: white;"></mdui-button-icon>
<mdui-top-app-bar-title style="text-align: center;color:white;">OpenAI API 信息查询</mdui-top-app-bar-title>
</mdui-top-app-bar>
<mdui-navigation-drawer open class="left-drawer" close-on-overlay-click>
<div class="left-drawer-main">
<h3>输入 API KEY</h3>
<p>本站不保存 KEY 信息,查询后请自行保存</p>
<mdui-text-field id="api-key-input" placeholder="请输入 API-KEY或sessID多个可直接粘贴" label="API-KEY或sessID"
rows="6"></mdui-text-field>
<mdui-select id="api-url-select" icon="airline_stops" label="查询线路" value="https://api.openai.com"
onchange="toggleCustomUrlInput()">
<mdui-menu-item value="https://api.openai.com">[官网线路]api.openai.com</mdui-menu-item>
<mdui-menu-item value="custom">[已前置https]自定义</mdui-menu-item>
</mdui-select>
<mdui-text-field type="text" id="custom-url-input" placeholder="如无前缀自动添加https://"
class="hidden"></mdui-text-field>
<div style="display: flex;">
<div id="progressbar-toggle" style="flex-grow: 1;">
<mdui-checkbox onchange="toggleProgressBar()">已用比例</mdui-checkbox>
</div> </div>
<div class="modal-body"> <div id="subinfo-toggle" style="flex-grow: 1;">
<p id="modalText"></p> <mdui-checkbox onchange="toggleSubInfo()">绑卡信息</mdui-checkbox>
</div> </div>
<div id="setid-toggle" style="flex-grow: 1;">
<mdui-checkbox onchange="toggleSetidInfo()">组织信息</mdui-checkbox>
</div> </div>
</div> </div>
<mdui-button full-width id="query-button" icon="search" onclick="sendRequest()">
查询
</mdui-button>
<footer>
<p>广告链接:
<a href="https://chat.czl.net" target="_blank">CZLChat</a> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<a href="https://oapi.czl.net" target="_blank">CZLOapi</a>
<br>
本网页由<a href="https://woodchen.ink" target="_blank">woodchen</a>开源于<a
href="https://github.com/woodchen-ink/openai-billing-query" target="_blank">Github</a>,欢迎给个star
</p>
</footer> <!-- 下半部分 -->
<script src="static/js.js"></script> <h4>页面列表</h4>
<mdui-menu style="width:100%;margin-top:20px;">
<mdui-menu-item icon="search" href="index.html">查API信息</mdui-menu-item>
<mdui-menu-item icon="vpn_key" href="get_sess.html">通过access token获取sess</mdui-menu-item>
<mdui-menu-item icon="vpn_key" href="get_sess2.html">通过PandoraNext获取sess</mdui-menu-item>
<mdui-menu-item icon="vpn_key" href="refresh_see.html">刷新Platform相关信息刷新sess</mdui-menu-item>
<mdui-menu-item icon="build" href="https://woodchen.ink/archives/how-to-query-the-balance-of-openai-in-batches-expires-gpt4-whether-to-tie-cards-1ov1aw"
target="_blank">手动获取sess的方法</mdui-menu-item>
</mdui-menu>
<div style="margin-top:20px;">
<mdui-chip elevated icon="code"> 本网页由<a href="https://woodchen.ink" target="_blank">woodchen</a>开源于<a
href="https://github.com/woodchen-ink/openai-billing-query" target="_blank">Github</a>
</mdui-chip>
</div>
</div>
</mdui-navigation-drawer>
</mdui-layout>
<script src="./static/js.js"></script>
</body> </body>

167
refresh_see.html Normal file
View File

@ -0,0 +1,167 @@
<!DOCTYPE html>
<html class="mdui-theme-light" lang="zh-cmn-Hans">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>刷新Platform相关信息刷新sess</title>
<meta
name="description"
content="批量快速查询OPENAI的余额支持可视化展现已用比例、额度、已用量、未用量、是否GPT-4、是否GPT4-32K、是否绑卡、绑卡信息、组织信息、是否有效"
/>
<link rel="stylesheet" href="./static/css-1.css" type="text/css" />
<link rel="stylesheet" href="./static/mdui/mdui.css" />
<script src="./static/mdui/mdui.global.js"></script>
<script>
mdui.setColorScheme("#0d2d44");
</script>
</head>
<body>
<style>
th,
td {
cursor: pointer; /* 添加鼠标指针样式 */
white-space: normal; /* 设置为normal使内容自动换行 */
word-wrap: break-word; /* 设置为break-word以确保长单词/链接被截断换行 */
max-width: 300px;
}
/* 复制按钮样式 */
.copy-button {
height: 36px;
cursor: pointer;
background-color: #4caf50;
color: white;
padding: 8px;
border: none;
border-radius: 4px;
margin: 8px 0;
margin-top: 20px;
margin-left: 20px;
}
</style>
<mdui-layout>
<mdui-layout-main>
<div class="mdui-main-container">
<div style="display: flex">
<h2 style="flex: 1">查询结果</h2>
<button class="copy-button" onclick="copySess()">复制sess</button>
<button class="copy-button" onclick="copyTable()">
复制全部内容
</button>
</div>
<div class="mdui-table">
<table id="result-table">
<thead>
<tr>
<th>序号</th>
<th>邮箱账户</th>
<th>手机号</th>
<th>Sensitive ID</th>
<th>Refresh Token</th>
<th>Access Token</th>
<th>Sensitive ID创建时间</th>
</tr>
</thead>
<tbody id="result-tbody" style="max-width: 100%">
<!-- 表格内容 -->
</tbody>
</table>
</div>
</div>
</mdui-layout-main>
<mdui-top-app-bar>
<mdui-button-icon
icon="menu"
close-on-overlay-click
id="toggle-button"
style="color: white"
></mdui-button-icon>
<mdui-top-app-bar-title style="text-align: center; color: white"
>刷新Platform相关信息刷新sess</mdui-top-app-bar-title
>
</mdui-top-app-bar>
<mdui-navigation-drawer open class="left-drawer" close-on-overlay-click>
<div class="left-drawer-main">
<h3>输入 API KEY</h3>
<p>本站不保存 KEY 信息,查询后请自行保存</p>
<mdui-text-field
id="api-key-input"
placeholder="请输入 refresh_token多个请回车换行"
label="refresh_token"
rows="6"
></mdui-text-field>
<mdui-select
id="api-url-select"
icon="airline_stops"
label="查询线路"
value="https://ai.fakeopen.com"
onchange="toggleCustomUrlInput()"
>
<mdui-menu-item value="https://ai.fakeopen.com"
>[FkopenAi]ai.fakeopen.com</mdui-menu-item
>
<mdui-menu-item value="custom">[已前置https]自定义PandoraNext API</mdui-menu-item>
</mdui-select>
<mdui-text-field
type="text"
id="custom-url-input"
placeholder="请输入PandoraNext的API地址和前缀"
label="PandoraNext API地址和前缀"
class="hidden"
></mdui-text-field>
<div style="height: 2rem"></div>
<mdui-button
full-width
id="query-button"
icon="search"
onclick="sendRequest()"
>
查询
</mdui-button>
<!-- 下半部分 -->
<h4>页面列表</h4>
<mdui-menu style="width: 100%; margin-top: 20px">
<mdui-menu-item icon="search" href="index.html"
>查API信息</mdui-menu-item
>
<mdui-menu-item icon="vpn_key" href="get_sess.html"
>通过access token获取sess</mdui-menu-item
>
<mdui-menu-item icon="vpn_key" href="get_sess2.html"
>通过PandoraNext获取sess</mdui-menu-item
>
<mdui-menu-item icon="vpn_key" href="refresh_see.html"
>刷新Platform相关信息刷新sess</mdui-menu-item
>
<mdui-menu-item
icon="build"
href="https://woodchen.ink/1266.html"
target="_blank"
>手动获取sess的方法</mdui-menu-item
>
</mdui-menu>
<div style="margin-top: 20px">
<mdui-chip elevated icon="code">
本网页由<a href="https://woodchen.ink" target="_blank">woodchen</a
>开源于<a
href="https://github.com/woodchen-ink/openai-billing-query"
target="_blank"
>Github</a
>
</mdui-chip>
</div>
</div>
</mdui-navigation-drawer>
</mdui-layout>
<script src="./static/refresh_see.js"></script>
</body>
</html>

55
static/css-1.css Normal file

File diff suppressed because one or more lines are too long

View File

@ -8,7 +8,7 @@
} }
body { body {
background: url('https://cdn-img.czl.net/2023/05/23/pjbczr.webp') no-repeat center center fixed; background: url('https://random-api.czl.net/pic/ecy') no-repeat center center fixed;
/* 自定义背景图 */ /* 自定义背景图 */
background-size: cover; background-size: cover;
width: 90%; width: 90%;
@ -19,7 +19,7 @@ body {
padding-right: 2rem; padding-right: 2rem;
color: var(--body-color); color: var(--body-color);
/* background: var(--body-bg); */ /* background: var(--body-bg); */
font-family: system-ui, -apple-system, 'Segoe UI', Helvetica, Arial, sans-serif; font-family: -apple-system,BlinkMacSystemFont,'Helvetica Neue',Helvetica,Segoe UI,Arial,Roboto,'PingFang SC',miui,'Hiragino Sans GB','Microsoft Yahei',sans-serif;
line-height: 1.5; line-height: 1.5;
-webkit-tap-highlight-color: rgb(252, 247, 247); -webkit-tap-highlight-color: rgb(252, 247, 247);
text-rendering: optimizelegibility; text-rendering: optimizelegibility;
@ -283,6 +283,10 @@ input#custom-url-input {
/* border: 1px solid #d3d3d3; */ /* border: 1px solid #d3d3d3; */
} }
/* #result-table tr{
border-radius: 8px;
} */
/* 下面的代码定义了结果表格奇数行的背景颜色 */ /* 下面的代码定义了结果表格奇数行的背景颜色 */
#result-table tbody tr:nth-child(odd) { #result-table tbody tr:nth-child(odd) {
background-color: #252422; background-color: #252422;
@ -352,13 +356,15 @@ button.loading::before {
/* 在小于768px的屏幕上生效的样式 */ /* 在小于768px的屏幕上生效的样式 */
/* 可以减小字体和表格单元格的大小,使其适应小屏设备 */ /* 可以减小字体和表格单元格的大小,使其适应小屏设备 */
#result-table th, #result-table td { #result-table th,
#result-table td {
font-size: 8px; font-size: 8px;
padding: 5px 3px; padding: 5px 3px;
} }
/* 可以隐藏一些不是非常重要的列,以便更有效地利用屏幕空间 */ /* 可以隐藏一些不是非常重要的列,以便更有效地利用屏幕空间 */
#result-table th:nth-child(n+12), #result-table td:nth-child(n+12) { #result-table th:nth-child(n+12),
#result-table td:nth-child(n+12) {
display: none; display: none;
} }
} }
@ -400,9 +406,11 @@ button.loading::before {
border-radius: 12px; border-radius: 12px;
white-space: pre-wrap; white-space: pre-wrap;
} }
.modal h2 { .modal h2 {
margin: 8px; margin: 8px;
} }
.modal p { .modal p {
margin-block-start: 0; margin-block-start: 0;
margin-block-end: 0; margin-block-end: 0;
@ -443,6 +451,3 @@ button.loading::before {
#modalText { #modalText {
margin: 0; margin: 0;
} }

224
static/getsess.js Normal file
View File

@ -0,0 +1,224 @@
let queriedApiKeys = [];
let serialNumber = 1;
function toggleCustomUrlInput() {
// 获取id为"api-url-select"的元素
const selectElement = document.getElementById("api-url-select");
// 获取id为"custom-url-input"的元素
const customUrlInput = document.getElementById("custom-url-input");
// 如果selectElement的值为"custom"
if (selectElement.value === "custom") {
// 从customUrlInput的classList中移除"hidden"
customUrlInput.classList.remove("hidden");
} else {
// 给customUrlInput的classList添加"hidden"
customUrlInput.classList.add("hidden");
}
}
async function checkBilling(apiKey, apiUrl) {
const headers = {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json"
};
const urlGetsess = `${apiUrl}/dashboard/onboarding/login`;
try {
const response = await fetch(urlGetsess, {
method: "POST", // 设置请求方法为 POST
headers: headers,
body: JSON.stringify({}) // 此处放置要发送的数据
});
const getsessdata = await response.json();
console.log(getsessdata);
if (getsessdata && getsessdata.user && getsessdata.user.session) {
return getsessdata; // 直接返回整个getsessdata对象
} else {
console.error("Unexpected data structure: user or session property not found in the response.", getsessdata);
return null;
}
} catch (error) {
console.error(error);
return null;
}
}
//查询函数
async function sendRequest() {
let apiKeyInput = document.getElementById("api-key-input");
let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input");
let table = document.getElementById("result-table");
let h2 = document.getElementById("result-head");
if (apiKeyInput.value.trim() === "") {
alert("请填写API KEY");
return;
}
document.getElementById("result-table").getElementsByTagName('tbody')[0].innerHTML = "";
let apiUrl = "";
if (apiUrlSelect.value === "custom") {
if (customUrlInput.value.trim() === "") {
mdui.alert({
headline: "无查询线路",
description: "请选择或自定义",
confirmText: "OK",
})
return;
} else {
apiUrl = customUrlInput.value.trim();
if (!apiUrl.startsWith("http://") && !apiUrl.startsWith("https://")) {
apiUrl = "https://" + apiUrl;
}
if (!apiUrl.startsWith("https://gateway.ai.cloudflare.com")) {
apiUrl += "/v1"; // 如果不是,则添加路径‘/v1
}
}
} else {
apiUrl = apiUrlSelect.value;
if (apiUrlSelect.value === "https://gateway.ai.cloudflare.com/v1/feedd0aa8abd6875052d86a94f1baf83/test/openai") {
apiUrl = apiUrl.replace("/v1", ""); // 如果用户选择的选项是https://gateway.ai.cloudflare.com开头则删除/v1
} else {
apiUrl += "/v1"; // 如果不是,则添加路径‘/v1
}
}
let apiKeys = apiKeyInput.value.split(/[,\s\n]+/);
if (apiKeys.length === 0) {
mdui.alert({
headline: "未匹配到 access_token",
description: "请检查输入内容",
confirmText: "OK",
})
return;
}
mdui.alert({
headline: "成功匹配到 access_token",
description: apiKeys,
confirmText: "OK",
});
showLoadingAnimation();
let tableBody = document.querySelector("#result-table tbody");
for (let i = 0; i < apiKeys.length; i++) {
let apiKey = apiKeys[i].trim();
let data = await checkBilling(apiKey, apiUrl); // 获取 checkBilling 的结果
let row = document.createElement("tr");
let serialNumberCell = document.createElement("td");
serialNumberCell.textContent = serialNumber;
row.appendChild(serialNumberCell);
let apiKeyCell = document.createElement("td");
apiKeyCell.textContent = apiKey.replace(/^(.{10}).*(.{8})$/, "$1***$2");
row.appendChild(apiKeyCell);
if (data.user && data.user.session) {
let user = data.user;
let session = user.session;
let ip_country = data.ip_country;
let orgId = user.orgs.data[0].id;
let properties = ['id', 'email', 'name', 'phone_number', 'created', 'sensitive_id', 'session_created', orgId, 'ip_country'];
properties.forEach(prop => {
let cell = document.createElement("td");
if (prop === 'created' || prop === 'session_created') {
let timestamp = prop === 'created' ? user[prop] : session['created'];
cell.textContent = new Date(timestamp * 1000).toLocaleString();
} else if (prop === 'sensitive_id') {
cell.textContent = session[prop]; // 获取 session 对象中的 sensitive_id
} else if (prop === orgId) {
cell.textContent = orgId; // 直接使用 orgId 变量
} else if (prop === 'ip_country') {
cell.textContent = ip_country ? ip_country : 'N/A'; // 改为使用 ip_country 变量
} else {
cell.textContent = user[prop];
}
row.appendChild(cell);
});
} else {
// 接口返回的数据结构不符合预期
console.error("Unexpected data structure: data[0] or data.user is undefined.");
let errorMessageCell = document.createElement("td");
errorMessageCell.colSpan = "8";
errorMessageCell.classList.add("status-error");
errorMessageCell.textContent = "不正确或已失效的API-KEY";
row.appendChild(errorMessageCell);
}
tableBody.appendChild(row);
if (i === apiKeys.length - 1) {
queriedApiKeys = [];
}
serialNumber++;
}
hideLoadingAnimation();
}
let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input");
apiUrlSelect.addEventListener("change", function () {
if (apiUrlSelect.value === "custom") {
customUrlInput.style.display = "inline-block";
customUrlInput.style.marginTop = "5px";
} else {
customUrlInput.style.display = "none";
}
});
function showLoadingAnimation() {
const button = document.getElementById("query-button");
// 创建一个新的 <mdui-linear-progress> 元素
const progressElement = document.createElement("mdui-linear-progress");
progressElement.id = "query-progress";
// 将新元素替代原始按钮元素
button.parentElement.replaceChild(progressElement, button);
}
function hideLoadingAnimation() {
const progressElement = document.querySelector("mdui-linear-progress");
if (progressElement) {
const button = document.createElement("mdui-button");
button.id = "query-button";
button.innerHTML = "查询";
button.setAttribute("full-width", "");
button.setAttribute("icon", "search");
button.setAttribute("onclick", "sendRequest()");
// 将原始按钮元素替代回来
progressElement.parentElement.replaceChild(button, progressElement);
}
}
let isOpen = true;
toggleButton.addEventListener("click", () => {
isOpen = !isOpen;
if (isOpen) {
navigationDrawer.open = true;
} else {
navigationDrawer.open = false;
}
});

247
static/getsess2.js Normal file
View File

@ -0,0 +1,247 @@
let serialNumber = 1;
function checkBilling(apiKey, apiUrl) {
return new Promise(async (resolve, reject) => {
const headers = {
"Content-Type": "application/x-www-form-urlencoded",
};
const urlGetsess = `${apiUrl}/api/auth/platform/login`;
var urlencoded = new URLSearchParams();
for (var i in apiKey) {
urlencoded.append(i, apiKey[i]);
}
try {
const response = await axios.post(urlGetsess, urlencoded, {
headers: headers,
maxRedirects: 0,
});
const getsessdata = response.data;
if (getsessdata && getsessdata.login_info && getsessdata.token_info) {
resolve(getsessdata); // 返回getsessdata对象
} else {
reject(getsessdata);
}
} catch (error) {
reject(error);
}
});
}
//查询函数
async function sendRequest() {
let apiKeyInput = document.getElementById("api-key-input");
let customUrlInput = document.getElementById("custom-url-input");
document
.getElementById("result-table")
.getElementsByTagName("tbody")[0].innerHTML = "";
let apiUrl = customUrlInput.value.trim();
if (apiUrl.endsWith('/')) {
apiUrl = apiUrl.slice(0, -1); // 去掉末尾的"/"
}
let userList = apiKeyInput.value.split(/[,\s\n]+/);
if (!apiUrl) {
mdui.alert({
headline: "无查询线路",
description: "请输入PandoraNext Api的地址",
confirmText: "OK",
});
return;
} else if (!apiUrl.startsWith("http://") && !apiUrl.startsWith("https://")) {
apiUrl = "https://" + apiUrl;
}
if (userList.length === 0) {
mdui.alert({
headline: "请检查输入内容",
description: "请填写账户信息",
confirmText: "OK",
});
return;
}
let userData = [];
for (var i = 0; i < userList.length; i++) {
var userInfo = userList[i].split(/\|/);
if (userInfo.length > 3 || userInfo.length < 2) {
mdui.alert({
headline: "请检查输入内容",
description: "请按格式输入账户信息",
confirmText: "OK",
});
return;
}
userData.push({
username: userInfo[0],
password: userInfo[1],
mfa_code: userInfo[2] ? userInfo[2] : "",
prompt: "login",
});
}
showLoadingAnimation();
let tableBody = document.querySelector("#result-table tbody");
let properties = [
"email",
"phone_number",
"sensitive_id",
"refresh_token",
"access_token",
"created",
];
for (let i = 0; i < userData.length; i++) {
let userInfo = userData[i];
let row = document.createElement("tr");
let serialNumberCell = document.createElement("td");
serialNumberCell.textContent = serialNumber;
row.appendChild(serialNumberCell);
try {
let data = await checkBilling(userInfo, apiUrl);
let user = data.login_info.user;
let session = user.session;
let token_info = data.token_info;
let cell = document.createElement("td");
let cellValue = '';
properties.forEach((prop) => {
console.log(prop);
let cell = document.createElement("td");
if (prop === "created") {
cellValue = new Date(session["created"] * 1000).toLocaleString();
} else if (prop === "sensitive_id") {
cellValue = session[prop]; // 获取 session 对象中的 sensitive_id
cell.onclick = function () {
copyCell(cell, `Sensitive ID复制成功`);
};
} else if (prop === "refresh_token" || prop === "access_token") {
cellValue = token_info[prop];
cell.onclick = function () {
copyCell(cell, `${prop === "refresh_token" ? 'Refresh Token' : 'Access Token'}复制成功`);
};
} else {
cellValue = user[prop] ? user[prop] : ''; // 确保在user[prop]为空时cellValue被赋予空字符串
}
cell.textContent = cellValue && cellValue.length > 50 ? cellValue.substring(0, 57) + "..." : cellValue; // 如果长度超过60显示"..."
cell.innerHTML = `<span title="${cellValue}">${cell.textContent}</span>`; // 在悬停时显示全部内容
row.appendChild(cell);
});
} catch (error) {
let username = document.createElement("td");
username.textContent = userInfo.username;
row.appendChild(username);
let errorMessageCell = document.createElement("td");
errorMessageCell.colSpan = "8";
errorMessageCell.classList.add("status-error");
// 在这里检查错误信息是否为 "error request login url"
if (error === 'error request login url') {
errorMessageCell.textContent = '请求错误,请稍后重试';
} else {
errorMessageCell.textContent = error && error.detail ? error.detail : error;
}
row.appendChild(errorMessageCell);
}
tableBody.appendChild(row);
serialNumber++;
}
hideLoadingAnimation();
}
function copyCell(cell, message) {
// 创建一个新的textarea元素
var textarea = document.createElement("textarea");
// 设置textarea的值为单元格的文本内容
textarea.value = cell.innerText;
// 将textarea元素添加到body中
document.body.appendChild(textarea);
// 选择textarea的文本内容
textarea.select();
// 执行复制命令
document.execCommand("copy");
// 移除textarea元素
document.body.removeChild(textarea);
mdui.alert({
headline: "提示",
description: message,
confirmText: "OK",
});
}
function copyTable() {
// 这个函数可以保留,以便你仍然可以复制整个表格内容
var tableBody = document.getElementById("result-tbody");
var textarea = document.createElement("textarea");
textarea.value = tableBody.innerText;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
mdui.alert({
headline: "提示",
description: "复制成功",
confirmText: "OK",
});
}
function copySess() {
var sensitiveCells = document.querySelectorAll("tbody td:nth-child(4) span"); // 选择所有的Sensitive ID单元格
var sensitiveIds = Array.from(sensitiveCells).map((cell) => cell.title); // 从单元格中获取所有的Sensitive ID
var textarea = document.createElement("textarea");
textarea.value = sensitiveIds.join("\n"); // 用换行符连接所有的Sensitive ID
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
mdui.alert({
headline: "提示",
description: "Sensitive ID复制成功",
confirmText: "OK",
});
}
function showLoadingAnimation() {
const button = document.getElementById("query-button");
// 创建一个新的 <mdui-linear-progress> 元素
const progressElement = document.createElement("mdui-linear-progress");
progressElement.id = "query-progress";
// 将新元素替代原始按钮元素
button.parentElement.replaceChild(progressElement, button);
}
function hideLoadingAnimation() {
const progressElement = document.querySelector("mdui-linear-progress");
if (progressElement) {
const button = document.createElement("mdui-button");
button.id = "query-button";
button.innerHTML = "查询";
button.setAttribute("full-width", "");
button.setAttribute("icon", "search");
button.setAttribute("onclick", "sendRequest()");
// 将原始按钮元素替代回来
progressElement.parentElement.replaceChild(button, progressElement);
}
}
const navigationDrawer = document.querySelector(".left-drawer");
const toggleButton = document.getElementById("toggle-button");
let isOpen = true;
toggleButton.addEventListener("click", () => {
isOpen = !isOpen;
if (isOpen) {
navigationDrawer.open = true;
} else {
navigationDrawer.open = false;
}
});

View File

@ -1,18 +1,69 @@
var modal = document.getElementById("myModal"); function toggleProgressBar() {
var span = document.getElementsByClassName("close")[0]; let progressBarHeader = document.getElementById("progressbar-header");
span.onclick = function () { let progressBarCells = document.querySelectorAll("td.progressbar");
modal.style.display = "none"; let toggle = document.querySelector("#progressbar-toggle mdui-checkbox");
} let display = toggle.checked ? "" : "none";
window.onclick = function (event) { progressBarHeader.style.display = display;
if (event.target == modal) { progressBarCells.forEach(function (cell) { cell.style.display = display; });
modal.style.display = "none";
} }
function toggleSubInfo() {
let toggle = document.querySelector("#subinfo-toggle mdui-checkbox");
let display = toggle.checked ? "" : "none";
let subInfoHeader = document.getElementById("subinfo-header");
subInfoHeader.style.display = display;
let subInfoCells = document.querySelectorAll("td.subinfo");
subInfoCells.forEach(function (cell) { cell.style.display = display; });
} }
function toggleSetidInfo() {
let toggle = document.querySelector("#setid-toggle mdui-checkbox");
let display = toggle.checked ? "" : "none";
let setIdHeader = document.getElementById("setid-header");
setIdHeader.style.display = display;
let setIdCells = document.querySelectorAll("td.setid");
setIdCells.forEach(function (cell) { cell.style.display = display; });
}
toggleProgressBar();
toggleSubInfo();
toggleSetidInfo();
// 线路选择框
function toggleCustomUrlInput() {
// 获取id为"api-url-select"的元素
const selectElement = document.getElementById("api-url-select");
// 获取id为"custom-url-input"的元素
const customUrlInput = document.getElementById("custom-url-input");
// 如果selectElement的值为"custom"
if (selectElement.value === "custom") {
// 从customUrlInput的classList中移除"hidden"
customUrlInput.classList.remove("hidden");
} else {
// 给customUrlInput的classList添加"hidden"
customUrlInput.classList.add("hidden");
}
}
let queriedApiKeys = []; let queriedApiKeys = [];
let serialNumber = 1; let serialNumber = 1;
/**
* 格式化日期
* @param {Date} date - 需要格式化的日期对象
* @returns {string} - 格式化后的日期字符串--
*/
function formatDate(date) {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
}
async function checkBilling(apiKey, apiUrl) { async function checkBilling(apiKey, apiUrl) {
const now = new Date(); const now = new Date();
@ -25,43 +76,72 @@ async function checkBilling(apiKey, apiUrl) {
"Authorization": "Bearer " + apiKey, "Authorization": "Bearer " + apiKey,
"Content-Type": "application/json" "Content-Type": "application/json"
}; };
const modelsCheck = `${apiUrl}/v1/models`; const modelsCheck = `${apiUrl}/models`;
const urlSubscription = `${apiUrl}/v1/dashboard/billing/subscription`; const urlSubscription = `${apiUrl}/dashboard/billing/subscription`;
let urlUsage = `${apiUrl}/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`; let urlUsage = `${apiUrl}/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`;
const urlsetid = apiUrl + '/v1/organizations'; const urlsetid = apiUrl + '/organizations';
const urlPaymentmethods = `${apiUrl}/v1/dashboard/billing/payment_methods`; const urlPaymentmethods = `${apiUrl}/dashboard/billing/payment_methods`;
const urlRatelimits = `${apiUrl}/v1/dashboard/rate_limits`; const urlRatelimits = `${apiUrl}/dashboard/rate_limits`;
const urlAdvanceData = `${apiUrl}/dashboard/billing/credit_grants`; // 预付费查询接口
try { try {
let totalAmount, totalUsage, remaining, GPT35CheckResult, GPT4CheckResult, GPT432kCheckResult, setid, isSubscrible; let totalAmount, totalUsage, remaining, GPT35CheckResult, GPT4CheckResult, GPT432kCheckResult, setid, isSubscrible;
let SubscribleInformation = {}; let SubscribleInformation = {};
let SubInformation; let SubInformation;
let errors = {}; let errors = {};
let response = await fetch(urlSubscription, { headers }); let response = await fetch(urlSubscription, { headers });
let currentDate = new Date(); let currentDate = new Date();
const subscriptionData = await response.json(); const subscriptionData = await response.json();
const expiryDate = new Date(subscriptionData.access_until * 1000 + 8 * 60 * 60 * 1000); const expiryDate = new Date(subscriptionData.access_until * 1000 + 8 * 60 * 60 * 1000);
const formattedDate = `${expiryDate.getFullYear()}-${(expiryDate.getMonth() + 1).toString().padStart(2, '0')}-${expiryDate.getDate().toString().padStart(2, '0')}`; const formattedDate = `${expiryDate.getFullYear()}-${(expiryDate.getMonth() + 1).toString().padStart(2, '0')}-${expiryDate.getDate().toString().padStart(2, '0')}`;
try { try {
totalAmount = subscriptionData.system_hard_limit_usd; // 将订阅数据中的硬限制金额赋值给totalAmount变量
totalAmount = subscriptionData.hard_limit_usd;
if (totalAmount > 20) { // 通过fetch函数获取advanceData数据传入urlAdvanceData和headers参数
startDate = subDate; const advanceDataResponse = await fetch(urlAdvanceData, { headers });
urlUsage = `${apiUrl}/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`; // 将响应解析为json格式
response = await fetch(urlUsage, { headers }); const advanceData = await advanceDataResponse.json();
const usageData = await response.json();
// 如果订阅数据的计费机制为'advance'或者总金额小于等于6并且订阅数据中没有信用卡信息
if ((subscriptionData.billing_mechanism === 'advance') || (totalAmount <= 6 && !subscriptionData.has_credit_card)) {
// 将advanceData中的total_granted属性值赋值给totalAmount变量
totalAmount = advanceData.total_granted;
} }
response = await fetch(urlUsage, { headers });
const usageData = await response.json();
totalUsage = usageData.total_usage / 100;
remaining = currentDate > expiryDate ? "❌过期" : (totalAmount - totalUsage).toFixed(3);
} catch (error) { } catch (error) {
// 捕获错误并打印到控制台
console.error(error); console.error(error);
errors['subscription'] = error.message;
} }
try {
// 如果总金额大于6
if (totalAmount > 6) {
// 设置开始日期为子日期
startDate = subDate;
// 构建请求使用数据的URL
urlUsage = `${apiUrl}/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`;
// 发送请求获取使用数据的响应
response = await fetch(urlUsage, { headers });
// 将响应解析为JSON格式的数据
const usageData = await response.json();
}
// 发送请求获取使用数据的响应
response = await fetch(urlUsage, { headers });
// 将响应解析为JSON格式的数据
const usageData = await response.json();
// 计算总使用量并除以100
totalUsage = usageData.total_usage / 100;
// 计算剩余金额并保留3位小数
remaining = (totalAmount - totalUsage).toFixed(3);
} catch (error) {
// 输出错误信息
console.error(error);
}
//获取是否绑卡 //获取是否绑卡
try { try {
if (subscriptionData.plan.id.includes('payg')) { if (subscriptionData.plan.id.includes('payg')) {
@ -84,17 +164,15 @@ async function checkBilling(apiKey, apiUrl) {
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }
//获取绑卡信息 //获取绑卡信息
try { try {
// 从 subscriptionData 中获取 SubscribleInformation 的值...
SubscribleInformation.account_name = subscriptionData.account_name; SubscribleInformation.account_name = subscriptionData.account_name;
SubscribleInformation.po_number = subscriptionData.po_number; SubscribleInformation.po_number = subscriptionData.po_number;
SubscribleInformation.billing_email = subscriptionData.billing_email; SubscribleInformation.billing_email = subscriptionData.billing_email;
SubscribleInformation.tax_ids = subscriptionData.tax_ids; SubscribleInformation.tax_ids = subscriptionData.tax_ids;
let billingAddress = subscriptionData.billing_address; // 定义并赋值 billingAddress let billingAddress = subscriptionData.billing_address;
let businessAddress = subscriptionData.business_address; // 定义并赋值 businessAddress let businessAddress = subscriptionData.business_address;
SubInformation = "名称: " + SubscribleInformation.account_name + "\n"; SubInformation = "名称: " + SubscribleInformation.account_name + "\n";
SubInformation += "PO号: " + SubscribleInformation.po_number + "\n"; SubInformation += "PO号: " + SubscribleInformation.po_number + "\n";
@ -104,7 +182,6 @@ async function checkBilling(apiKey, apiUrl) {
SubInformation += "账单地址: " + (billingAddress?.line1 ? billingAddress.line1 : '') + ", " + (billingAddress?.city ? billingAddress.city : '') + ", " + (billingAddress?.state ? billingAddress.state : '') + ", " + (billingAddress?.country ? billingAddress.country : '') + ", " + (billingAddress?.postal_code ? billingAddress.postal_code : '') + "\n"; SubInformation += "账单地址: " + (billingAddress?.line1 ? billingAddress.line1 : '') + ", " + (billingAddress?.city ? billingAddress.city : '') + ", " + (billingAddress?.state ? billingAddress.state : '') + ", " + (billingAddress?.country ? billingAddress.country : '') + ", " + (billingAddress?.postal_code ? billingAddress.postal_code : '') + "\n";
SubInformation += "商业地址: " + (businessAddress?.line1 ? businessAddress.line1 : '') + ", " + (businessAddress?.city ? businessAddress.city : '') + ", " + (businessAddress?.state ? businessAddress.state : '') + ", " + (businessAddress?.country ? businessAddress.country : '') + ", " + (businessAddress?.postal_code ? businessAddress.postal_code : '\n'); SubInformation += "商业地址: " + (businessAddress?.line1 ? businessAddress.line1 : '') + ", " + (businessAddress?.city ? businessAddress.city : '') + ", " + (businessAddress?.state ? businessAddress.state : '') + ", " + (businessAddress?.country ? businessAddress.country : '') + ", " + (businessAddress?.postal_code ? businessAddress.postal_code : '\n');
// 获取付款方法信息
response = await fetch(urlPaymentmethods, { headers }); response = await fetch(urlPaymentmethods, { headers });
const paymentMethodsData = await response.json(); const paymentMethodsData = await response.json();
@ -126,7 +203,6 @@ async function checkBilling(apiKey, apiUrl) {
catch (error) { catch (error) {
console.error(error); console.error(error);
} }
//组织信息 //组织信息
try { try {
response = await fetch(urlsetid, { headers }); response = await fetch(urlsetid, { headers });
@ -140,12 +216,9 @@ async function checkBilling(apiKey, apiUrl) {
const description = setiddata.data[0].description; const description = setiddata.data[0].description;
const createdTimestamp = setiddata.data[0].created; const createdTimestamp = setiddata.data[0].created;
const createdDate = new Date(createdTimestamp * 1000); const createdDate = new Date(createdTimestamp * 1000);
// 格式化日期 // 格式化日期
const formattedDate = `${createdDate.getFullYear()}.${(createdDate.getMonth() + 1).toString().padStart(2, '0')}.${createdDate.getDate().toString().padStart(2, '0')}`; const formattedDate = `${createdDate.getFullYear()}.${(createdDate.getMonth() + 1).toString().padStart(2, '0')}.${createdDate.getDate().toString().padStart(2, '0')}`;
const timeAndZone = createdDate.toString().match(/\d{2}:\d{2}:\d{2} \w+/)[0]; const timeAndZone = createdDate.toString().match(/\d{2}:\d{2}:\d{2} \w+/)[0];
if (typeof setiddata.data[1] !== 'undefined') { if (typeof setiddata.data[1] !== 'undefined') {
const id2 = setiddata.data[1].id; const id2 = setiddata.data[1].id;
setid = `${title}\n${email}\n${id1}\n${id2}\n${name}\n${description}\n${formattedDate} ${timeAndZone}`; setid = `${title}\n${email}\n${id1}\n${id2}\n${name}\n${description}\n${formattedDate} ${timeAndZone}`;
@ -163,7 +236,6 @@ async function checkBilling(apiKey, apiUrl) {
console.error(error); console.error(error);
errors['setid'] = error.message; errors['setid'] = error.message;
} }
//获取速率 //获取速率
let rateLimits; let rateLimits;
try { try {
@ -179,9 +251,6 @@ async function checkBilling(apiKey, apiUrl) {
console.error(error); console.error(error);
errors['rateLimits'] = error.message; errors['rateLimits'] = error.message;
} }
// 初始化模型查询结果 // 初始化模型查询结果
GPT35CheckResult = '❌'; GPT35CheckResult = '❌';
GPT4CheckResult = '❌'; GPT4CheckResult = '❌';
@ -191,43 +260,41 @@ async function checkBilling(apiKey, apiUrl) {
try { try {
const modelsCheckResponse = await fetch(modelsCheck, { headers }); const modelsCheckResponse = await fetch(modelsCheck, { headers });
const modelsCheckData = await modelsCheckResponse.json(); const modelsCheckData = await modelsCheckResponse.json();
GPT35CheckSuccess = GPT35CheckResult = Array.isArray(modelsCheckData.data) && modelsCheckData.data.some(item => item.id.includes('gpt-3.5-turbo')) ? '✅' : '❌'; GPT35CheckSuccess = GPT35CheckResult = Array.isArray(modelsCheckData.data) && modelsCheckData.data.some(item => item.id.includes('gpt-3.5-turbo')) ? '✅' : '❌';
} catch (error) {
console.error(error);
errors['modelsCheck'] = error.message;
}
//4模型查询
try {
const modelsCheckResponse = await fetch(modelsCheck, { headers });
const modelsCheckData = await modelsCheckResponse.json();
GPT4CheckResult = Array.isArray(modelsCheckData.data) && modelsCheckData.data.some(item => item.id.includes('gpt-4')) ? '✅' : '❌'; GPT4CheckResult = Array.isArray(modelsCheckData.data) && modelsCheckData.data.some(item => item.id.includes('gpt-4')) ? '✅' : '❌';
GPT432kCheckResult = Array.isArray(modelsCheckData.data) && modelsCheckData.data.some(item => item.id.includes('gpt-4-32k')) ? '✅' : '❌'; GPT432kCheckResult = Array.isArray(modelsCheckData.data) && modelsCheckData.data.some(item => item.id.includes('gpt-4-32k')) ? '✅' : '❌';
} catch (error) { } catch (error) {
console.error(error); console.error(error);
errors['modelsCheck'] = error.message;
} }
// 是否有效查询
// 发起请求查有效
async function checkCompletion(apiKey, apiUrl) { async function checkCompletion(apiKey, apiUrl) {
const urlCompletion = `${apiUrl}/v1/chat/completions`; // 设置请求的url
const urlCompletion = `${apiUrl}/chat/completions`;
// 设置请求头
const headers = { const headers = {
"Authorization": "Bearer " + apiKey, "Authorization": "Bearer " + apiKey,
"Content-Type": "application/json" "Content-Type": "application/json"
}; };
// 设置请求体
const postBody = JSON.stringify({ const postBody = JSON.stringify({
"model": "gpt-3.5-turbo", "model": "gpt-3.5-turbo",
"messages": [{ "messages": [{
"role": "user", "role": "user",
"content": "Hello" "content": "hi"
}], }],
"max_tokens": 5 "max_tokens": 1
}); });
// 发起请求
let response = await fetch(urlCompletion, { let response = await fetch(urlCompletion, {
method: 'POST', method: 'POST',
headers: headers, headers: headers,
body: postBody body: postBody
}); });
// 获取响应数据
let data = await response.json(); let data = await response.json();
// 判断请求是否成功 // 判断请求是否成功
if (response.status === 200) { if (response.status === 200) {
@ -247,67 +314,110 @@ async function checkBilling(apiKey, apiUrl) {
function formatDate(date) {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
}
//查询函数 //查询函数
function sendRequest() { function sendRequest() {
let button = document.querySelector("button"); toggleProgressBar();
button.textContent = "加载中..."; toggleSubInfo();
button.disabled = true; toggleSetidInfo();
button.classList.add("loading")
let apiKeyInput = document.getElementById("api-key-input"); let apiKeyInput = document.getElementById("api-key-input");
let apiUrlSelect = document.getElementById("api-url-select"); let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input"); let customUrlInput = document.getElementById("custom-url-input");
let table = document.getElementById("result-table"); let table = document.getElementById("result-table");
let h2 = document.getElementById("result-head");
h2.style.visibility = "visible";
table.style.visibility = "visible"; table.style.visibility = "visible";
if (apiKeyInput.value.trim() === "") { if (apiKeyInput.value.trim() === "") {
alert("请填写API KEY"); mdui.alert({
headline: "未匹配到 API-KEY",
description: "请检查输入内容",
confirmText: "OK",
})
return; return;
} }
document.getElementById("result-table").getElementsByTagName('tbody')[0].innerHTML = ""; document.getElementById("result-table").getElementsByTagName('tbody')[0].innerHTML = "";
let apiUrl = ""; let apiUrl = "";
// 判断用户选择的API URL选项
if (apiUrlSelect.value === "custom") { if (apiUrlSelect.value === "custom") {
if (customUrlInput.value.trim() === "") { if (customUrlInput.value.trim() === "") {
alert("请设置API链接"); mdui.alert({
headline: "无查询线路",
description: "请选择或自定义",
confirmText: "OK",
})
return; return;
} else { } else {
apiUrl = customUrlInput.value.trim(); apiUrl = customUrlInput.value.trim();
if (!apiUrl.startsWith("http://") && !apiUrl.startsWith("https://")) { if (!apiUrl.startsWith("http://") && !apiUrl.startsWith("https://")) {
apiUrl = "https://" + apiUrl; apiUrl = "https://" + apiUrl;
} }
if (!apiUrl.startsWith("https://gateway.ai.cloudflare.com")) {
apiUrl += "/v1"; // 如果不是,则添加路径‘/v1
}
} }
} else { } else {
apiUrl = apiUrlSelect.value; apiUrl = apiUrlSelect.value;
if (apiUrlSelect.value === "https://gateway.ai.cloudflare.com/v1/feedd0aa8abd6875052d86a94f1baf83/test/openai") {
apiUrl = apiUrl.replace("/v1", ""); // 如果用户选择的选项是https://gateway.ai.cloudflare.com开头则删除/v1
} else {
apiUrl += "/v1"; // 如果不是,则添加路径‘/v1
}
} }
let apiKeys = apiKeyInput.value.split(/[,\s\n]+/);
if (apiKeys.length === 0) {
alert("未匹配到 API-KEY请检查输入内容"); let apiKeys = parseKeys(apiKeyInput.value);
return;
mdui.alert({
headline: "成功匹配到 API Key",
description: apiKeys,
confirmText: "OK",
});
showLoadingAnimation();
function parseKeys(input) {
let lines = input.split(/\n/);
let result = [];
for (let line of lines) {
let sessKeyMatch = line.match(/sess-[^-]+/);
let skKeyMatch = line.match(/sk-[^-]+/);
if (sessKeyMatch !== null && skKeyMatch !== null) {
result.push(sessKeyMatch[0]);
}
else if (skKeyMatch !== null) {
result.push(skKeyMatch[0]);
}
else if (sessKeyMatch !== null) {
result.push(sessKeyMatch[0]);
}else {
// 如果没有匹配到任何内容,保留原始行
result.push(line);
}
}
return result;
} }
alert("成功匹配到 API Key确认后开始查询" + apiKeys);
let lastQueryPromise = null;
let tableBody = document.querySelector("#result-table tbody"); let tableBody = document.querySelector("#result-table tbody");
for (let i = 0; i < apiKeys.length; i++) { for (let i = 0; i < apiKeys.length; i++) {
let apiKey = apiKeys[i].trim(); let apiKey = apiKeys[i].trim();
if (queriedApiKeys.includes(apiKey)) { if (queriedApiKeys.includes(apiKey)) {
console.log(`API KEY ${apiKey} 已查询过,跳过此次查询`); mdui.alert({
headline: "重复提示",
description: `API KEY ${apiKey} 已查询过,跳过此次查询`,
confirmText: "OK"
})
continue; continue;
} }
queriedApiKeys.push(apiKey); queriedApiKeys.push(apiKey);
@ -321,12 +431,11 @@ function sendRequest() {
} }
} }
) )
let row = document.createElement("tr"); let row = document.createElement("tr");
let serialNumberCell = document.createElement("td"); // 创建序列号单元格 let serialNumberCell = document.createElement("td"); // 创建序列号单元格
serialNumberCell.textContent = serialNumber; // 设置序列号文本 serialNumberCell.textContent = serialNumber;
row.appendChild(serialNumberCell); // 将序列号单元格添加到行中 row.appendChild(serialNumberCell);
let apiKeyCell = document.createElement("td"); let apiKeyCell = document.createElement("td");
apiKeyCell.textContent = apiKey.replace(/^(.{5}).*(.{4})$/, "$1***$2"); apiKeyCell.textContent = apiKey.replace(/^(.{5}).*(.{4})$/, "$1***$2");
@ -334,29 +443,30 @@ function sendRequest() {
console.log('查看查询结果', data); // 添加 console.log 以查看 data 的值 console.log('查看查询结果', data); // 添加 console.log 以查看 data 的值
if (data[0] === undefined) {
let errorMessageCell = document.createElement("td");
errorMessageCell.colSpan = "8";
errorMessageCell.classList.add("status-error");
errorMessageCell.textContent = "不正确或已失效的API-KEY";
row.appendChild(errorMessageCell);
} else {
let totalAmount = document.createElement("td"); let totalAmount = document.createElement("td");
totalAmount.textContent = data[0]; totalAmount.textContent = typeof data[0] === "number" ? data[0] : "无值";
row.appendChild(totalAmount); row.appendChild(totalAmount);
let totalUsedCell = document.createElement("td"); let totalUsedCell = document.createElement("td");
if (!isNaN(data[1])) { typeof data[1] === "number" ? data[1].toFixed(3) : '无值';
totalUsedCell.textContent = data[1].toFixed(3); if (isNaN(data[1])) {
totalUsedCell.textContent = "无值";
} else { } else {
totalUsedCell.textContent = '❌' totalUsedCell.textContent = data[1].toFixed(3);
} }
row.appendChild(totalUsedCell); row.appendChild(totalUsedCell);
let totalAvailableCell = document.createElement("td"); let totalAvailableCell = document.createElement("td");
totalAvailableCell.textContent = typeof data[2] === 'number' ? data[2] : data[2]; if (isNaN(data[2])) {
totalAvailableCell.textContent = "无值";
} else {
totalAvailableCell.textContent = data[2];
}
row.appendChild(totalAvailableCell); row.appendChild(totalAvailableCell);
// 进度条
let progressCell = document.createElement("td"); let progressCell = document.createElement("td");
progressCell.classList.add("progressbar");
let progressContainer = document.createElement("div"); // 添加一个新的容器元素 let progressContainer = document.createElement("div"); // 添加一个新的容器元素
progressContainer.style.width = "100%"; progressContainer.style.width = "100%";
progressContainer.style.height = "20px"; progressContainer.style.height = "20px";
@ -373,69 +483,70 @@ function sendRequest() {
progressContainer.appendChild(progressBar); // 将进度条添加到容器中 progressContainer.appendChild(progressBar); // 将进度条添加到容器中
progressCell.appendChild(progressContainer); // 将容器添加到单元格中 progressCell.appendChild(progressContainer); // 将容器添加到单元格中
row.appendChild(progressCell); row.appendChild(progressCell);
progressCell.style.display = document.querySelector("#progressbar-toggle mdui-checkbox").checked ? "" : "none";
function createSeeMoreLink(text) {
let seeMoreLink = document.createElement("a");
seeMoreLink.href = "#";
seeMoreLink.textContent = '全部';
seeMoreLink.style.cursor = "pointer";
seeMoreLink.style.textDecoration = "underline";
seeMoreLink.onclick = (event) => {
event.preventDefault();
document.getElementById('modalText').textContent = text;
document.getElementById('myModal').style.display = "block";
};
return seeMoreLink;
}
// 到期时间
let expireTime = document.createElement("td"); let expireTime = document.createElement("td");
if (data[3] === "1970-01-01") {
expireTime.textContent = "永久有效";
} else if (data[3] === "NaN-NaN-NaN") {
expireTime.textContent = "无值";
} else {
expireTime.textContent = data[3]; expireTime.textContent = data[3];
}
row.appendChild(expireTime); row.appendChild(expireTime);
let GPT35CheckResult = document.createElement("td"); let GPT35CheckResult = document.createElement("td");
GPT35CheckResult.textContent = data[4]; GPT35CheckResult.textContent = data[4];
row.appendChild(GPT35CheckResult);
let GPT4CheckResult = document.createElement("td"); let GPT4CheckResult = document.createElement("td");
GPT4CheckResult.textContent = data[5]; GPT4CheckResult.textContent = data[5];
row.appendChild(GPT4CheckResult);
let GPT432kCheckResult = document.createElement("td"); let GPT432kCheckResult = document.createElement("td");
GPT432kCheckResult.textContent = data[6]; GPT432kCheckResult.textContent = data[6];
row.appendChild(GPT432kCheckResult); let highestModel = document.createElement("td");
if (GPT35CheckResult.textContent === "✅" && GPT4CheckResult.textContent === "❌" && GPT432kCheckResult.textContent === "❌") {
highestModel.textContent = "gpt3.5";
} else if (GPT35CheckResult.textContent === "✅" && GPT4CheckResult.textContent === "✅" && GPT432kCheckResult.textContent === "❌") {
highestModel.textContent = "gpt4";
} else if (GPT35CheckResult.textContent === "✅" && GPT4CheckResult.textContent === "✅" && GPT432kCheckResult.textContent === "✅") {
highestModel.textContent = "gpt4-32K";
} else {
highestModel.textContent = "❌";
}
row.appendChild(highestModel);
let isSubscribe = document.createElement("td"); let isSubscribe = document.createElement("td");
isSubscribe.style.whiteSpace = "pre"; // 添加这一行来保留换行 isSubscribe.style.whiteSpace = "pre"; // 添加这一行来保留换行
isSubscribe.textContent = data[7]; isSubscribe.textContent = data[7];
if (data[7] === "Not Found.") {
isSubscribe.textContent = "无值";
} else {
isSubscribe.textContent = data[7];
}
row.appendChild(isSubscribe); row.appendChild(isSubscribe);
let SubInformation = document.createElement("td"); let SubInformation = document.createElement("td");
SubInformation.classList.add("subinfo");
let SubInformationContainer = document.createElement("div"); let SubInformationContainer = document.createElement("div");
SubInformationContainer.style.whiteSpace = "pre-wrap"; SubInformationContainer.style.whiteSpace = "pre-wrap";
if (data[8].length > 50) {
SubInformationContainer.textContent = data[8].slice(0, 25) + '... ';
SubInformationContainer.appendChild(createSeeMoreLink(data[8]));
} else {
SubInformationContainer.textContent = data[8]; SubInformationContainer.textContent = data[8];
}
SubInformation.appendChild(SubInformationContainer); SubInformation.appendChild(SubInformationContainer);
row.appendChild(SubInformation); row.appendChild(SubInformation);
SubInformation.style.display = document.querySelector("#subinfo-toggle mdui-checkbox").checked ? "" : "none";
let setidCell = document.createElement("td"); let setidCell = document.createElement("td");
setidCell.classList.add("setid");
let setidCellContainer = document.createElement("div"); let setidCellContainer = document.createElement("div");
setidCellContainer.style.whiteSpace = "pre-wrap"; setidCellContainer.style.whiteSpace = "pre-wrap";
if (data[9].length > 50) {
setidCellContainer.textContent = data[9].slice(0, 25) + '... ';
setidCellContainer.appendChild(createSeeMoreLink(data[9]));
} else {
setidCellContainer.textContent = data[9]; setidCellContainer.textContent = data[9];
}
setidCell.appendChild(setidCellContainer); setidCell.appendChild(setidCellContainer);
row.appendChild(setidCell); row.appendChild(setidCell);
setidCell.style.display = document.querySelector("#setid-toggle mdui-checkbox").checked ? "" : "none";
let rateLimitsDataCell = document.createElement("td"); let rateLimitsDataCell = document.createElement("td");
@ -447,18 +558,23 @@ function sendRequest() {
let rateLimitsText = ''; let rateLimitsText = '';
for (let model of models) { for (let model of models) {
if (rateLimitsData[model]) { if (rateLimitsData[model]) {
rateLimitsText += `${model}:\n\tRPM: ${rateLimitsData[model].max_requests_per_1_minute}\n\tTPM: ${rateLimitsData[model].max_tokens_per_1_minute}\n\n`; let modelName = '';
if (model === 'gpt-3.5-turbo') {
modelName = 'gpt3.5';
} else if (model === 'gpt-3.5-turbo-16k') {
modelName = 'gpt3.5-16K';
} else if (model === 'gpt-4') {
modelName = 'gpt4';
} else if (model === 'gpt-4-32k') {
modelName = 'gpt4-32K';
}
rateLimitsText += `${modelName}: ${rateLimitsData[model].max_requests_per_1_minute}, ${rateLimitsData[model].max_tokens_per_1_minute}-${rateLimitsData[model].max_requests_per_1_day}\n`;
} else { } else {
rateLimitsText += model + ": ❌\n"; rateLimitsText += model + ": ❌\n";
} }
} }
if (rateLimitsText.length > 50) {
rateLimitsDataContainer.textContent = rateLimitsText.slice(0, 25) + '... ';
rateLimitsDataContainer.appendChild(createSeeMoreLink(rateLimitsText));
} else {
rateLimitsDataContainer.textContent = rateLimitsText; rateLimitsDataContainer.textContent = rateLimitsText;
} }
}
rateLimitsDataCell.appendChild(rateLimitsDataContainer); rateLimitsDataCell.appendChild(rateLimitsDataContainer);
row.appendChild(rateLimitsDataCell); row.appendChild(rateLimitsDataCell);
@ -470,32 +586,70 @@ function sendRequest() {
row.appendChild(completionCheckResultCell); row.appendChild(completionCheckResultCell);
}
tableBody.appendChild(row); tableBody.appendChild(row);
if (i === apiKeys.length - 1) { if (i === apiKeys.length - 1) {
queriedApiKeys = []; queriedApiKeys = [];
} }
serialNumber++; // 增加序列号 serialNumber++; // 增加序列号
h2.style.display = 'block';
table.style.display = 'table'; table.style.display = 'table';
button.textContent = "查询";
button.disabled = false;
button.classList.remove("loading")
}) })
lastQueryPromise = checkBilling(apiKey, apiUrl).then((data) => {
// 查询完成后的代码...
hideLoadingAnimation();
});
}
if (lastQueryPromise) {
lastQueryPromise.then(() => {
hideLoadingAnimation();
});
}
}
function showLoadingAnimation() {
const button = document.getElementById("query-button");
// 创建一个新的 <mdui-linear-progress> 元素
const progressElement = document.createElement("mdui-linear-progress");
progressElement.id = "query-progress";
// 将新元素替代原始按钮元素
button.parentElement.replaceChild(progressElement, button);
}
function hideLoadingAnimation() {
const progressElement = document.querySelector("mdui-linear-progress");
if (progressElement) {
const button = document.createElement("mdui-button");
button.id = "query-button";
button.innerHTML = "查询";
button.setAttribute("full-width", "");
button.setAttribute("icon", "search");
button.setAttribute("onclick", "sendRequest()");
// 将原始按钮元素替代回来
progressElement.parentElement.replaceChild(button, progressElement);
} }
} }
let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input");
apiUrlSelect.addEventListener("change", function () {
if (apiUrlSelect.value === "custom") { const navigationDrawer = document.querySelector(".left-drawer");
customUrlInput.style.display = "inline-block"; const toggleButton = document.getElementById("toggle-button");
customUrlInput.style.marginTop = "5px";
let isOpen = true;
toggleButton.addEventListener("click", () => {
isOpen = !isOpen;
if (isOpen) {
navigationDrawer.open = true;
} else { } else {
customUrlInput.style.display = "none"; navigationDrawer.open = false;
} }
}); });

1
static/mdui/mdui.css Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

279
static/refresh_see.js Normal file
View File

@ -0,0 +1,279 @@
let serialNumber = 1;
// 线路选择框
function toggleCustomUrlInput() {
// 获取id为"api-url-select"的元素
const selectElement = document.getElementById("api-url-select");
// 获取id为"custom-url-input"的元素
const customUrlInput = document.getElementById("custom-url-input");
// 如果selectElement的值为"custom"
if (selectElement.value === "custom") {
// 从customUrlInput的classList中移除"hidden"
customUrlInput.classList.remove("hidden");
} else {
// 给customUrlInput的classList添加"hidden"
customUrlInput.classList.add("hidden");
}
}
function checkBilling(apiKey, apiUrl) {
return new Promise(async (resolve, reject) => {
try {
// 拼接url
var tokenUrl = `${apiUrl}`;
var loginUrl = `${apiUrl}/v1/dashboard/onboarding/login`;
// 使用"/auth/platform/refresh",潘多拉则需要加上/api
if (!apiUrl.startsWith("https://ai.fakeopen.com")) {
tokenUrl += "/api";
}
tokenUrl += "/auth/platform/refresh";
var urlencoded = new URLSearchParams();
urlencoded.append("refresh_token", apiKey);
let response = await fetch(tokenUrl, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: urlencoded,
redirect: "follow",
});
const rdata = await response.json();
if (rdata && rdata.access_token && rdata.refresh_token) {
// 查询sess
const get_sess = await fetch(loginUrl, {
method: "POST", // 设置请求方法为 POST
headers: {
Authorization: "Bearer " + rdata.access_token,
"Content-Type": "application/json",
},
body: JSON.stringify({}), // 此处放置要发送的数据
});
const getsessdata = await get_sess.json();
if (getsessdata && getsessdata.user && getsessdata.user.session) {
resolve({ token_info: rdata, ...getsessdata });
} else {
reject(getsessdata);
}
} else {
reject(rdata);
}
} catch (error) {
reject(error);
}
});
}
//查询函数
async function sendRequest() {
let apiKeyInput = document.getElementById("api-key-input");
let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input");
document
.getElementById("result-table")
.getElementsByTagName("tbody")[0].innerHTML = "";
let apiUrl = apiUrlSelect.value;
if (apiUrlSelect.value === "custom") {
apiUrl = customUrlInput.value.trim();
}
if (!apiUrl) {
mdui.alert({
headline: "无查询线路",
description: "请选择或自定义配置查询Sess线路",
confirmText: "OK",
});
return;
} else {
if (!apiUrl.startsWith("http://") && !apiUrl.startsWith("https://")) {
apiUrl = "https://" + apiUrl;
}
if (apiUrl && apiUrl.endsWith("/")) {
apiUrl = apiUrl.slice(0, -1); // 去掉末尾的"/"
}
}
let tokenList = apiKeyInput.value.split(/[,\s\n]+/);
if (!apiKeyInput.value || tokenList.length === 0) {
mdui.alert({
headline: "请输入Token",
description: "请检查输入refresh_token",
confirmText: "OK",
});
return;
}
showLoadingAnimation();
let tableBody = document.querySelector("#result-table tbody");
let properties = [
"email",
"phone_number",
"sensitive_id",
"refresh_token",
"access_token",
"created",
];
for (let i = 0; i < tokenList.length; i++) {
let token = tokenList[i].trim();
if (token) {
let row = document.createElement("tr");
let serialNumberCell = document.createElement("td");
serialNumberCell.textContent = serialNumber;
row.appendChild(serialNumberCell);
try {
let data = await checkBilling(token, apiUrl);
let user = data.user;
let session = user.session;
let token_info = data.token_info;
properties.forEach((prop) => {
let cellValue = "";
let cell = document.createElement("td");
if (prop === "created") {
cellValue = new Date(session["created"] * 1000).toLocaleString();
} else if (prop === "sensitive_id") {
cellValue = session[prop]; // 获取 session 对象中的 sensitive_id
cell.onclick = function () {
copyCell(cell, `Sensitive ID复制成功`);
};
} else if (prop === "refresh_token" || prop === "access_token") {
cellValue = token_info[prop];
cell.onclick = function () {
copyCell(
cell,
`${
prop === "refresh_token" ? "Refresh Token" : "Access Token"
}复制成功`
);
};
} else {
cellValue = user[prop] ? user[prop] : ""; // 确保在user[prop]为空时cellValue被赋予空字符串
}
cell.textContent =
cellValue && cellValue.length > 50
? cellValue.substring(0, 57) + "..."
: cellValue; // 如果长度超过60显示"..."
cell.innerHTML = `<span title="${cellValue}">${cell.textContent}</span>`; // 在悬停时显示全部内容
row.appendChild(cell);
});
} catch (error) {
let username = document.createElement("td");
username.textContent = token.replace(/^(.{10}).*(.{8})$/, "$1***$2");
row.appendChild(username);
let errorMessageCell = document.createElement("td");
errorMessageCell.colSpan = "8";
errorMessageCell.classList.add("status-error");
// 在这里检查错误信息是否为 "error request login url"
if (error === "error request login url") {
errorMessageCell.textContent = "请求错误,请稍后重试";
} else {
errorMessageCell.textContent =
error && error.detail ? error.detail : error;
}
row.appendChild(errorMessageCell);
}
tableBody.appendChild(row);
serialNumber++;
}
}
hideLoadingAnimation();
}
function copyCell(cell, message) {
// 创建一个新的textarea元素
var textarea = document.createElement("textarea");
// 设置textarea的值为单元格的文本内容
textarea.value = cell.innerText;
// 将textarea元素添加到body中
document.body.appendChild(textarea);
// 选择textarea的文本内容
textarea.select();
// 执行复制命令
document.execCommand("copy");
// 移除textarea元素
document.body.removeChild(textarea);
mdui.alert({
headline: "提示",
description: message,
confirmText: "OK",
});
}
function copyTable() {
// 这个函数可以保留,以便你仍然可以复制整个表格内容
var tableBody = document.getElementById("result-tbody");
var textarea = document.createElement("textarea");
textarea.value = tableBody.innerText;
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
mdui.alert({
headline: "提示",
description: "复制成功",
confirmText: "OK",
});
}
function copySess() {
var sensitiveCells = document.querySelectorAll("tbody td:nth-child(4) span"); // 选择所有的Sensitive ID单元格
var sensitiveIds = Array.from(sensitiveCells).map((cell) => cell.title); // 从单元格中获取所有的Sensitive ID
var textarea = document.createElement("textarea");
textarea.value = sensitiveIds.join("\n"); // 用换行符连接所有的Sensitive ID
document.body.appendChild(textarea);
textarea.select();
document.execCommand("copy");
document.body.removeChild(textarea);
mdui.alert({
headline: "提示",
description: "Sensitive ID复制成功",
confirmText: "OK",
});
}
function showLoadingAnimation() {
const button = document.getElementById("query-button");
// 创建一个新的 <mdui-linear-progress> 元素
const progressElement = document.createElement("mdui-linear-progress");
progressElement.id = "query-progress";
// 将新元素替代原始按钮元素
button.parentElement.replaceChild(progressElement, button);
}
function hideLoadingAnimation() {
const progressElement = document.querySelector("mdui-linear-progress");
if (progressElement) {
const button = document.createElement("mdui-button");
button.id = "query-button";
button.innerHTML = "查询";
button.setAttribute("full-width", "");
button.setAttribute("icon", "search");
button.setAttribute("onclick", "sendRequest()");
// 将原始按钮元素替代回来
progressElement.parentElement.replaceChild(button, progressElement);
}
}
const navigationDrawer = document.querySelector(".left-drawer");
const toggleButton = document.getElementById("toggle-button");
let isOpen = true;
toggleButton.addEventListener("click", () => {
isOpen = !isOpen;
if (isOpen) {
navigationDrawer.open = true;
} else {
navigationDrawer.open = false;
}
});

28
tailwind.config.js Normal file
View File

@ -0,0 +1,28 @@
module.exports = {
theme: {
screens: {
"sm": "640px",
"md": "768px",
"lg": "1024px",
"xl": "1280px",
"2xl": "1600px",
'sm': '576px',
"2xl": { 'max': '1600px' },
// => @media (min-width: 576px) { ... }
'md': '960px',
// => @media (min-width: 960px) { ... }
'lg': '1560px',
// => @media (min-width: 1440px) { ... }
}
},
plugins: [require("daisyui")],
variants: {
extend: {
borderColor: ['responsive', 'hover', 'focus']
}
}
}