Appearance
Appearance
<script setup lang="ts">
import { ref } from 'vue'
import { ElButton, ElInput,ElForm,ElFormItem,ElNotification,ElTable,ElTableColumn,ElSwitch } from 'element-plus'
const f= ref({text:"",apiUrl:'https://api.openai.com',isShowAll: true})
interface gptType{
apiKey:string
totalAmount?:string|number
totalUsage?:string|number
remaining?:string|number
formattedDate?:string|number
GPT4CheckResult?:string|number
GPT432kCheckResult?:string|number
isSubscrible?:string|number
setid?:string|number
}
const list=ref<gptType[]>([]);
const showMsg=(msg:string)=>{
ElNotification.info({
message: msg
})
}
const 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}`;
}
const checkBilling= async (apiKey :string, apiUrl:string)=> {
// 计算起始日期和结束日期,当前为 90 天,最大不超过100天
const now = new Date();
let startDate = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000);
const endDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);
const subDate = new Date(now);
subDate.setDate(1);
// 设置API请求URL和请求头
const headers = {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json"
};
const gpt4Check = `${apiUrl}/v1/models`;
const urlSubscription = `${apiUrl}/v1/dashboard/billing/subscription`;
let urlUsage = `${apiUrl}/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`;
const urlsetid = apiUrl + '/v1/organizations'; //查组织id
try {
// 获取API限额
let response = await fetch(urlSubscription, { headers });
if (!response.ok) {
console.log("APIKEY 错误或账号被封,请登录 OpenAI 查看。");
return;
}
let currentDate = new Date();
const subscriptionData = await response.json();
const totalAmount = subscriptionData.system_hard_limit_usd;
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 gpt4CheckResponse = await fetch(gpt4Check, { headers });
const gpt4CheckData = await gpt4CheckResponse.json();
let GPT4CheckResult = Array.isArray(gpt4CheckData.data) && gpt4CheckData.data.some(item => item.id.includes('gpt-4')) ? '✅' : '❌';
let GPT432kCheckResult = Array.isArray(gpt4CheckData.data) && gpt4CheckData.data.some(item => item.id.includes('gpt-4-32k')) ? '✅' : '❌';
let isSubscrible = subscriptionData.plan.id.includes('payg') ? '✅' : '❌';
if (totalAmount > 20) {
startDate = subDate;
urlUsage = `${apiUrl}/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`;
response = await fetch(urlUsage, { headers });
const usageData = await response.json();
}
response = await fetch(urlUsage, { headers });
const usageData = await response.json();
const totalUsage = usageData.total_usage / 100;
let remaining;
if (currentDate > expiryDate) {
remaining = "❌过期";
} else {
remaining = subscriptionData.system_hard_limit_usd - totalUsage;
}
//查询组织id
response = await fetch(urlsetid, { headers });
const setiddata = await response.json();
let setid = '';
if (typeof setiddata.data[1] !== 'undefined') {
setid = setiddata.data[0].id + '----' + setiddata.data[1].id;
} else {
setid = setiddata.data[0].id;
}
return {apiKey,totalAmount, totalUsage, remaining, formattedDate, GPT4CheckResult, GPT432kCheckResult,isSubscrible, setid};
} catch (error) {
console.error(error);
//return ["Error", null, null, null, null,null, null, null];
return {apiKey,totalAmount:'Error', totalUsage:'...', remaining:'...', formattedDate:'...', GPT4CheckResult:'...', GPT432kCheckResult:'...',isSubscrible:'...', setid:'...'}
}
}
const go= async ()=>{
const txt = f.value.text;
if(txt.trim()==''){
showMsg('请输入sk');
return;
}
let skKeys = txt.match(/sk-[A-Za-z0-9]{48}/g);
let sessKeys = txt.match(/sess-[A-Za-z0-9]{40}/g);
const apiKeys = sessKeys || skKeys || [];
if (apiKeys.length == 0) {
showMsg('请输入sk');
return;
}
list.value= apiKeys.map(v=>{
const a:gptType = {apiKey: v }
return a ;
});
showMsg(`总共有${apiKeys.length}个key`);
//list.value.forEach( (v,i )=>{
for(let i=0;i<list.value.length;i++){
let v= list.value[i];
v.formattedDate='Loading';
list.value[i]=v;
try{
let data = await checkBilling(v.apiKey,f.value.apiUrl);
v={...v,...data};
if(typeof v.totalUsage == 'number' ) v.totalUsage=v.totalUsage.toFixed(2);
if( typeof v.totalAmount=='number') v.totalAmount=v.totalAmount.toFixed(2);
if( typeof v.remaining=='number') v.remaining=v.remaining.toFixed(2);
list.value[i]=v;
}catch(e){
v.formattedDate='请求失败';
list.value[i]=v;
}
}
//})
}
</script>
<template>
<ElForm>
<ElFormItem >
<ElInput v-model="f.apiUrl" placeholder="https://api.openai.com 也可以是代理" >
<template #prepend>网关地址</template>
</ElInput>
</ElFormItem>
<ElFormItem >
<ElInput v-model="f.text" :autosize="{ minRows: 4, maxRows: 15 }" type="textarea"
placeholder="请输入ssee key 或者 api key ;全贴进来会识别的,支持多个"
/>
</ElFormItem>
<ElFormItem >
<ElSwitch v-model="f.isShowAll" active-text="显示全部" />
</ElFormItem>
<ElFormItem >
<ElButton type="primary" @click="go()" :disabled="f.text==''">查询余额</ElButton>
</ElFormItem>
</ElForm>
<div style=" margin: 20px 0 ;">
<ElTable :data="list" style="width: 100%" size="small">
<ElTableColumn prop="apiKey" label="KEY" />
<ElTableColumn prop="totalAmount" label="额度" width="70" align="center" />
<ElTableColumn prop="remaining" label="余额" width="70" align="center" />
<ElTableColumn prop="totalUsage" label="使用" width="70" align="center" />
<ElTableColumn prop="formattedDate" label="到期" width="100" align="center"/>
<ElTableColumn prop="GPT4CheckResult" label="GPT4" align="center" width="55" v-if="f.isShowAll"/>
<ElTableColumn prop="GPT432kCheckResult" label="32K" align="center" width="55" v-if="f.isShowAll"/>
<ElTableColumn prop="isSubscrible" label="绑卡" align="center" width="55" v-if="f.isShowAll" />
</ElTable>
</div>
</template>