diff --git a/service/package.json b/service/package.json
index 4b74e5a..6311f31 100644
--- a/service/package.json
+++ b/service/package.json
@@ -24,6 +24,7 @@
"common:cleanup": "rimraf node_modules && rimraf pnpm-lock.yaml"
},
"dependencies": {
+ "axios": "^1.3.4",
"chatgpt": "^5.0.10",
"dotenv": "^16.0.3",
"esno": "^0.16.3",
diff --git a/service/pnpm-lock.yaml b/service/pnpm-lock.yaml
index e2e251f..8e4b85e 100644
--- a/service/pnpm-lock.yaml
+++ b/service/pnpm-lock.yaml
@@ -4,6 +4,7 @@ specifiers:
'@antfu/eslint-config': ^0.35.3
'@types/express': ^4.17.17
'@types/node': ^18.14.6
+ axios: ^1.3.4
chatgpt: ^5.0.10
dotenv: ^16.0.3
eslint: ^8.35.0
@@ -18,6 +19,7 @@ specifiers:
typescript: ^4.9.5
dependencies:
+ axios: 1.3.4
chatgpt: 5.0.10
dotenv: 16.0.3
esno: 0.16.3
@@ -766,6 +768,10 @@ packages:
es-shim-unscopables: 1.0.0
dev: true
+ /asynckit/0.4.0:
+ resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
+ dev: false
+
/atomically/2.0.1:
resolution: {integrity: sha512-sxBhVZUFBFhqSAsYMM3X2oaUi2NVDJ8U026FsIusM8gYXls9AYs/eXzgGrufs1Qjpkxi9zunds+75QUFz+m7UQ==}
dependencies:
@@ -778,6 +784,16 @@ packages:
engines: {node: '>= 0.4'}
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:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
@@ -966,6 +982,13 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
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:
resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
engines: {node: '>= 6'}
@@ -1082,6 +1105,11 @@ packages:
object-keys: 1.1.1
dev: true
+ /delayed-stream/1.0.0:
+ resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
+ engines: {node: '>=0.4.0'}
+ dev: false
+
/depd/2.0.0:
resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==}
engines: {node: '>= 0.8'}
@@ -1852,12 +1880,31 @@ packages:
resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==}
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:
resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==}
dependencies:
is-callable: 1.2.7
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:
resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==}
engines: {node: '>=12.20.0'}
@@ -2918,6 +2965,10 @@ packages:
ipaddr.js: 1.9.1
dev: false
+ /proxy-from-env/1.1.0:
+ resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==}
+ dev: false
+
/punycode/2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
diff --git a/service/src/chatgpt/index.ts b/service/src/chatgpt/index.ts
index 7b20d23..b76c780 100644
--- a/service/src/chatgpt/index.ts
+++ b/service/src/chatgpt/index.ts
@@ -5,6 +5,7 @@ import { ChatGPTAPI, ChatGPTUnofficialProxyAPI } from 'chatgpt'
import { SocksProxyAgent } from 'socks-proxy-agent'
import { HttpsProxyAgent } from 'https-proxy-agent'
import fetch from 'node-fetch'
+import axios from 'axios'
import { sendResponse } from '../utils'
import { isNotEmptyString } from '../utils/is'
import type { ApiModel, ChatContext, ChatGPTUnofficialProxyAPIOptions, ModelConfig } from '../types'
@@ -99,14 +100,35 @@ async function chatReplyProcess(
}
}
-async function chatConfig() {
- const reverseProxy = process.env.API_REVERSE_PROXY ?? '-'
- const socksProxy = (process.env.SOCKS_PROXY_HOST && process.env.SOCKS_PROXY_PORT) ? (`${process.env.SOCKS_PROXY_HOST}:${process.env.SOCKS_PROXY_PORT}`) : '-'
- const httpsProxy = (process.env.HTTPS_PROXY || process.env.ALL_PROXY) ?? '-'
+async function fetchBalance() {
+ const OPENAI_API_KEY = process.env.OPENAI_API_KEY
+ if (!isNotEmptyString(OPENAI_API_KEY))
+ 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
{{ $t("setting.api") }}:{{ config?.apiModel ?? '-' }}
+{{ $t("setting.balance") }}:{{ config?.balance ?? '-' }}
{{ $t("setting.reverseProxy") }}:{{ config?.reverseProxy ?? '-' }}
{{ $t("setting.timeout") }}:{{ config?.timeoutMs ?? '-' }}
{{ $t("setting.socks") }}:{{ config?.socksProxy ?? '-' }}
diff --git a/src/locales/en-US.ts b/src/locales/en-US.ts index b1b88ba..0e9e3d3 100644 --- a/src/locales/en-US.ts +++ b/src/locales/en-US.ts @@ -63,6 +63,7 @@ export default { timeout: 'Timeout', socks: 'Socks', httpsProxy: 'HTTPS Proxy', + balance: 'API Balance', }, store: { local: 'Local', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index 813b637..e47b850 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -63,6 +63,7 @@ export default { timeout: '超时', socks: 'Socks', httpsProxy: 'HTTPS Proxy', + balance: 'API余额', }, store: { local: '本地', diff --git a/src/locales/zh-TW.ts b/src/locales/zh-TW.ts index 3ed65df..2b8ffda 100644 --- a/src/locales/zh-TW.ts +++ b/src/locales/zh-TW.ts @@ -63,6 +63,7 @@ export default { timeout: '逾時', socks: 'Socks', httpsProxy: 'HTTPS Proxy', + balance: 'API余額', }, store: { local: '本機',