Compare commits

..

No commits in common. "4cfd0ef0909e1ae690eb41c688990b5bb30f4317" and "cec28df931fc201b68154bdd7630b73ac3ac2879" have entirely different histories.

View File

@ -1,7 +1,7 @@
""" """
Admin balance fetchers for Kimi (Moonshot), DeepSeek, and Qwen (Aliyun BSS). Admin balance fetchers for Kimi (Moonshot), DeepSeek, and Qwen (Aliyun BSS).
Credentials (优先读取仓库根目录 .env其次环境变量): Credentials (read from environment):
- MOONSHOT_API_KEY : Bearer token for Kimi - MOONSHOT_API_KEY : Bearer token for Kimi
- DEEPSEEK_API_KEY : Bearer token for DeepSeek - DEEPSEEK_API_KEY : Bearer token for DeepSeek
- ALIYUN_ACCESS_KEY_ID : AccessKey ID for Aliyun (Qwen billing) - ALIYUN_ACCESS_KEY_ID : AccessKey ID for Aliyun (Qwen billing)
@ -18,44 +18,11 @@ import json
import os import os
import time import time
import uuid import uuid
from pathlib import Path
from typing import Any, Dict, Tuple from typing import Any, Dict, Tuple
from urllib import parse, request from urllib import parse, request, error
# -------- .env 读取助手 --------
_DOTENV_CACHE: Dict[str, str] | None = None
def _read_dotenv() -> Dict[str, str]: USD_CNY_RATE = float(os.environ.get("USD_CNY_RATE", "7.1"))
global _DOTENV_CACHE
if _DOTENV_CACHE is not None:
return _DOTENV_CACHE
path = Path(__file__).resolve().parents[1] / ".env"
result: Dict[str, str] = {}
if path.exists():
try:
for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
key = key.strip()
value = value.strip().strip('"').strip("'")
if key:
result[key] = value
except Exception:
pass
_DOTENV_CACHE = result
return result
def _env(key: str, default: str | None = None) -> str | None:
if key in os.environ:
return os.environ[key]
return _read_dotenv().get(key, default)
USD_CNY_RATE = float(_env("USD_CNY_RATE", "7.1") or "7.1")
def _http_get(url: str, headers: Dict[str, str] | None = None, timeout: int = 8) -> Tuple[Dict[str, Any] | None, str | None]: def _http_get(url: str, headers: Dict[str, str] | None = None, timeout: int = 8) -> Tuple[Dict[str, Any] | None, str | None]:
@ -71,17 +38,11 @@ def _http_get(url: str, headers: Dict[str, str] | None = None, timeout: int = 8)
# -------- Kimi (Moonshot) -------- # -------- Kimi (Moonshot) --------
def fetch_kimi_balance() -> Dict[str, Any]: def fetch_kimi_balance() -> Dict[str, Any]:
api_key = _env("MOONSHOT_API_KEY") or _env("API_KEY_KIMI") or _env("AGENT_API_KEY") api_key = os.environ.get("MOONSHOT_API_KEY")
if not api_key: if not api_key:
return {"success": False, "error": "Kimi 密钥未设置MOONSHOT_API_KEY / API_KEY_KIMI / AGENT_API_KEY"} return {"success": False, "error": "MOONSHOT_API_KEY 未设置"}
base = ( url = "https://api.moonshot.ai/v1/users/me/balance"
_env("API_BASE_KIMI")
or _env("MOONSHOT_BASE_URL")
or _env("AGENT_API_BASE_URL")
or "https://api.moonshot.ai/v1"
).rstrip("/")
url = f"{base}/users/me/balance"
payload, err = _http_get(url, headers={"Authorization": f"Bearer {api_key}"}) payload, err = _http_get(url, headers={"Authorization": f"Bearer {api_key}"})
if err: if err:
return {"success": False, "error": err} return {"success": False, "error": err}
@ -93,10 +54,12 @@ def fetch_kimi_balance() -> Dict[str, Any]:
cash = float(data.get("cash_balance", 0)) cash = float(data.get("cash_balance", 0))
return { return {
"success": True, "success": True,
"currency": payload.get("currency") or "CNY", "currency": "USD",
"available": available, "available": available,
"available_cny": round(available * USD_CNY_RATE, 2),
"voucher": voucher, "voucher": voucher,
"cash": cash, "cash": cash,
"rate": USD_CNY_RATE,
"raw": payload, "raw": payload,
} }
except Exception as exc: # pragma: no cover except Exception as exc: # pragma: no cover
@ -105,9 +68,9 @@ def fetch_kimi_balance() -> Dict[str, Any]:
# -------- DeepSeek -------- # -------- DeepSeek --------
def fetch_deepseek_balance() -> Dict[str, Any]: def fetch_deepseek_balance() -> Dict[str, Any]:
api_key = _env("DEEPSEEK_API_KEY") or _env("API_KEY_DEEPSEEK") api_key = os.environ.get("DEEPSEEK_API_KEY")
if not api_key: if not api_key:
return {"success": False, "error": "DeepSeek 密钥未设置DEEPSEEK_API_KEY / API_KEY_DEEPSEEK"} return {"success": False, "error": "DEEPSEEK_API_KEY 未设置"}
url = "https://api.deepseek.com/user/balance" url = "https://api.deepseek.com/user/balance"
payload, err = _http_get(url, headers={"Authorization": f"Bearer {api_key}"}) payload, err = _http_get(url, headers={"Authorization": f"Bearer {api_key}"})
@ -147,8 +110,8 @@ def _sign(params: Dict[str, Any], secret: str) -> str:
def fetch_qwen_balance() -> Dict[str, Any]: def fetch_qwen_balance() -> Dict[str, Any]:
ak = _env("ALIYUN_ACCESS_KEY_ID") ak = os.environ.get("ALIYUN_ACCESS_KEY_ID")
sk = _env("ALIYUN_ACCESS_KEY_SECRET") sk = os.environ.get("ALIYUN_ACCESS_KEY_SECRET")
if not ak or not sk: if not ak or not sk:
return {"success": False, "error": "缺少 ALIYUN_ACCESS_KEY_ID / ALIYUN_ACCESS_KEY_SECRET"} return {"success": False, "error": "缺少 ALIYUN_ACCESS_KEY_ID / ALIYUN_ACCESS_KEY_SECRET"}
@ -165,10 +128,7 @@ def fetch_qwen_balance() -> Dict[str, Any]:
} }
signature = _sign(params, sk) signature = _sign(params, sk)
params["Signature"] = signature params["Signature"] = signature
url = "https://bss.aliyuncs.com/?" + parse.urlencode(params)
# 按阿里云规范组装最终查询字符串(不可用 urlencode 的 quote_plus
query = "&".join(f"{_percent_encode(k)}={_percent_encode(v)}" for k, v in params.items())
url = "https://business.aliyuncs.com/?" + query
payload, err = _http_get(url) payload, err = _http_get(url)
if err: if err:
@ -196,3 +156,4 @@ def fetch_all_balances() -> Dict[str, Any]:
"deepseek": fetch_deepseek_balance(), "deepseek": fetch_deepseek_balance(),
"qwen": fetch_qwen_balance(), "qwen": fetch_qwen_balance(),
} }