feat: show api balance (#582)
* feat: show api balance * Update index.ts * 保留小数点后五位 * perf: 判断优化 --------- Co-authored-by: Redon <790348264@qq.com>
This commit is contained in:
parent
116ed7b0bf
commit
e46d3685a0
|
@ -24,6 +24,7 @@
|
||||||
"common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml"
|
"common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"axios": "^1.3.4",
|
||||||
"chatgpt": "^5.0.10",
|
"chatgpt": "^5.0.10",
|
||||||
"dotenv": "^16.0.3",
|
"dotenv": "^16.0.3",
|
||||||
"esno": "^0.16.3",
|
"esno": "^0.16.3",
|
||||||
|
|
|
@ -4,6 +4,7 @@ specifiers:
|
||||||
'@antfu/eslint-config': ^0.35.3
|
'@antfu/eslint-config': ^0.35.3
|
||||||
'@types/express': ^4.17.17
|
'@types/express': ^4.17.17
|
||||||
'@types/node': ^18.14.6
|
'@types/node': ^18.14.6
|
||||||
|
axios: ^1.3.4
|
||||||
chatgpt: ^5.0.10
|
chatgpt: ^5.0.10
|
||||||
dotenv: ^16.0.3
|
dotenv: ^16.0.3
|
||||||
eslint: ^8.35.0
|
eslint: ^8.35.0
|
||||||
|
@ -18,6 +19,7 @@ specifiers:
|
||||||
typescript: ^4.9.5
|
typescript: ^4.9.5
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
|
axios: 1.3.4
|
||||||
chatgpt: 5.0.10
|
chatgpt: 5.0.10
|
||||||
dotenv: 16.0.3
|
dotenv: 16.0.3
|
||||||
esno: 0.16.3
|
esno: 0.16.3
|
||||||
|
@ -766,6 +768,10 @@ packages:
|
||||||
es-shim-unscopables: 1.0.0
|
es-shim-unscopables: 1.0.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/asynckit/0.4.0:
|
||||||
|
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/atomically/2.0.1:
|
/atomically/2.0.1:
|
||||||
resolution: {integrity: sha512-sxBhVZUFBFhqSAsYMM3X2oaUi2NVDJ8U026FsIusM8gYXls9AYs/eXzgGrufs1Qjpkxi9zunds+75QUFz+m7UQ==}
|
resolution: {integrity: sha512-sxBhVZUFBFhqSAsYMM3X2oaUi2NVDJ8U026FsIusM8gYXls9AYs/eXzgGrufs1Qjpkxi9zunds+75QUFz+m7UQ==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -778,6 +784,16 @@ packages:
|
||||||
engines: {node: '>= 0.4'}
|
engines: {node: '>= 0.4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/axios/1.3.4:
|
||||||
|
resolution: {integrity: sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==}
|
||||||
|
dependencies:
|
||||||
|
follow-redirects: 1.15.2
|
||||||
|
form-data: 4.0.0
|
||||||
|
proxy-from-env: 1.1.0
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- debug
|
||||||
|
dev: false
|
||||||
|
|
||||||
/balanced-match/1.0.2:
|
/balanced-match/1.0.2:
|
||||||
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -966,6 +982,13 @@ packages:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/combined-stream/1.0.8:
|
||||||
|
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||||
|
engines: {node: '>= 0.8'}
|
||||||
|
dependencies:
|
||||||
|
delayed-stream: 1.0.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
/commander/4.1.1:
|
/commander/4.1.1:
|
||||||
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -1082,6 +1105,11 @@ packages:
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/delayed-stream/1.0.0:
|
||||||
|
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
|
||||||
|
engines: {node: '>=0.4.0'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/depd/2.0.0:
|
/depd/2.0.0:
|
||||||
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
@ -1852,12 +1880,31 @@ packages:
|
||||||
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
|
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/follow-redirects/1.15.2:
|
||||||
|
resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==}
|
||||||
|
engines: {node: '>=4.0'}
|
||||||
|
peerDependencies:
|
||||||
|
debug: '*'
|
||||||
|
peerDependenciesMeta:
|
||||||
|
debug:
|
||||||
|
optional: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/for-each/0.3.3:
|
/for-each/0.3.3:
|
||||||
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
|
||||||
dependencies:
|
dependencies:
|
||||||
is-callable: 1.2.7
|
is-callable: 1.2.7
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/form-data/4.0.0:
|
||||||
|
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dependencies:
|
||||||
|
asynckit: 0.4.0
|
||||||
|
combined-stream: 1.0.8
|
||||||
|
mime-types: 2.1.35
|
||||||
|
dev: false
|
||||||
|
|
||||||
/formdata-polyfill/4.0.10:
|
/formdata-polyfill/4.0.10:
|
||||||
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
|
||||||
engines: {node: '>=12.20.0'}
|
engines: {node: '>=12.20.0'}
|
||||||
|
@ -2918,6 +2965,10 @@ packages:
|
||||||
ipaddr.js: 1.9.1
|
ipaddr.js: 1.9.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/proxy-from-env/1.1.0:
|
||||||
|
resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/punycode/2.3.0:
|
/punycode/2.3.0:
|
||||||
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
|
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { ChatGPTAPI, ChatGPTUnofficialProxyAPI } from 'chatgpt'
|
||||||
import { SocksProxyAgent } from 'socks-proxy-agent'
|
import { SocksProxyAgent } from 'socks-proxy-agent'
|
||||||
import { HttpsProxyAgent } from 'https-proxy-agent'
|
import { HttpsProxyAgent } from 'https-proxy-agent'
|
||||||
import fetch from 'node-fetch'
|
import fetch from 'node-fetch'
|
||||||
|
import axios from 'axios'
|
||||||
import { sendResponse } from '../utils'
|
import { sendResponse } from '../utils'
|
||||||
import { isNotEmptyString } from '../utils/is'
|
import { isNotEmptyString } from '../utils/is'
|
||||||
import type { ApiModel, ChatContext, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types'
|
import type { ApiModel, ChatContext, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types'
|
||||||
|
@ -99,14 +100,35 @@ async function chatReplyProcess(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function chatConfig() {
|
async function fetchBalance() {
|
||||||
const reverseProxy = process.env.API_REVERSE_PROXY ?? '-'
|
const OPENAI_API_KEY = process.env.OPENAI_API_KEY
|
||||||
const socksProxy = (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`) : '-'
|
if (!isNotEmptyString(OPENAI_API_KEY))
|
||||||
const httpsProxy = (process.env.HTTPS_PROXY || process.env.ALL_PROXY) ?? '-'
|
return Promise.resolve('-')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const headers = {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${OPENAI_API_KEY}`,
|
||||||
|
}
|
||||||
|
const response = await axios.get('https://api.openai.com/dashboard/billing/credit_grants', { headers })
|
||||||
|
const balance = response.data.total_available ?? 0
|
||||||
|
return Promise.resolve(balance.toFixed(3))
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
return Promise.resolve('-')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function chatConfig() {
|
||||||
|
const balance = await fetchBalance()
|
||||||
|
const reverseProxy = process.env.API_REVERSE_PROXY ?? '-'
|
||||||
|
const httpsProxy = (process.env.HTTPS_PROXY || process.env.ALL_PROXY) ?? '-'
|
||||||
|
const socksProxy = (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT)
|
||||||
|
? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`)
|
||||||
|
: '-'
|
||||||
return sendResponse<ModelConfig>({
|
return sendResponse<ModelConfig>({
|
||||||
type: 'Success',
|
type: 'Success',
|
||||||
data: { apiModel, reverseProxy, timeoutMs, socksProxy, httpsProxy },
|
data: { apiModel, reverseProxy, timeoutMs, socksProxy, httpsProxy, balance },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +155,10 @@ function setupProxy(options: ChatGPTAPIOptions | ChatGPTUnofficialProxyAPIOption
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function currentModel(): ApiModel {
|
||||||
|
return apiModel
|
||||||
|
}
|
||||||
|
|
||||||
export type { ChatContext, ChatMessage }
|
export type { ChatContext, ChatMessage }
|
||||||
|
|
||||||
export { chatReplyProcess, chatConfig }
|
export { chatReplyProcess, chatConfig, currentModel }
|
||||||
|
|
|
@ -20,6 +20,7 @@ export interface ModelConfig {
|
||||||
timeoutMs?: number
|
timeoutMs?: number
|
||||||
socksProxy?: string
|
socksProxy?: string
|
||||||
httpsProxy?: string
|
httpsProxy?: string
|
||||||
|
balance?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ApiModel = 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' | undefined
|
export type ApiModel = 'ChatGPTAPI' | 'ChatGPTUnofficialProxyAPI' | undefined
|
||||||
|
|
|
@ -10,6 +10,7 @@ interface ConfigState {
|
||||||
apiModel?: string
|
apiModel?: string
|
||||||
socksProxy?: string
|
socksProxy?: string
|
||||||
httpsProxy?: string
|
httpsProxy?: string
|
||||||
|
balance?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
@ -55,6 +56,7 @@ onMounted(() => {
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<p>{{ $t("setting.api") }}:{{ config?.apiModel ?? '-' }}</p>
|
<p>{{ $t("setting.api") }}:{{ config?.apiModel ?? '-' }}</p>
|
||||||
|
<p>{{ $t("setting.balance") }}:{{ config?.balance ?? '-' }}</p>
|
||||||
<p>{{ $t("setting.reverseProxy") }}:{{ config?.reverseProxy ?? '-' }}</p>
|
<p>{{ $t("setting.reverseProxy") }}:{{ config?.reverseProxy ?? '-' }}</p>
|
||||||
<p>{{ $t("setting.timeout") }}:{{ config?.timeoutMs ?? '-' }}</p>
|
<p>{{ $t("setting.timeout") }}:{{ config?.timeoutMs ?? '-' }}</p>
|
||||||
<p>{{ $t("setting.socks") }}:{{ config?.socksProxy ?? '-' }}</p>
|
<p>{{ $t("setting.socks") }}:{{ config?.socksProxy ?? '-' }}</p>
|
||||||
|
|
|
@ -63,6 +63,7 @@ export default {
|
||||||
timeout: 'Timeout',
|
timeout: 'Timeout',
|
||||||
socks: 'Socks',
|
socks: 'Socks',
|
||||||
httpsProxy: 'HTTPS Proxy',
|
httpsProxy: 'HTTPS Proxy',
|
||||||
|
balance: 'API Balance',
|
||||||
},
|
},
|
||||||
store: {
|
store: {
|
||||||
local: 'Local',
|
local: 'Local',
|
||||||
|
|
|
@ -63,6 +63,7 @@ export default {
|
||||||
timeout: '超时',
|
timeout: '超时',
|
||||||
socks: 'Socks',
|
socks: 'Socks',
|
||||||
httpsProxy: 'HTTPS Proxy',
|
httpsProxy: 'HTTPS Proxy',
|
||||||
|
balance: 'API余额',
|
||||||
},
|
},
|
||||||
store: {
|
store: {
|
||||||
local: '本地',
|
local: '本地',
|
||||||
|
|
|
@ -63,6 +63,7 @@ export default {
|
||||||
timeout: '逾時',
|
timeout: '逾時',
|
||||||
socks: 'Socks',
|
socks: 'Socks',
|
||||||
httpsProxy: 'HTTPS Proxy',
|
httpsProxy: 'HTTPS Proxy',
|
||||||
|
balance: 'API余額',
|
||||||
},
|
},
|
||||||
store: {
|
store: {
|
||||||
local: '本機',
|
local: '本機',
|
||||||
|
|
Loading…
Reference in New Issue