346 lines
12 KiB
Python
346 lines
12 KiB
Python
import os
|
|
import random
|
|
import time
|
|
from typing import List, Optional, Dict
|
|
from threading import Lock
|
|
import requests
|
|
|
|
# 4090dify 中用的硅基流动 apikey
|
|
# sk-iuyfpcewztavgnivrllwnegffvrrsyeiuwvjrabngtejsqwy
|
|
# sk-skynrwfqvipknbcvjsxkhjaqlivmocpkdppkocjndbyulado
|
|
# sk-gjeanmnxtfcqezqagixyexarlxeztkazbrsciqescrfxrgpw
|
|
# sk-uapywdmjaylwwyufaivraqwbpqtxjpbsbkltlrmwqftvfech
|
|
# sk-dwmxnhaeephbxgsfncbonyajubuhuyhsfqwfsxahlepkiwas
|
|
# sk-lnxedlpzufrurrmvylugpccnppwyqdccgeiicoijrqnslcgm
|
|
# sk-duccaryfxcrpvwrbwvjbuwjwazyqleyebumhvrutksuqbxug
|
|
# sk-njcrhxpvevtxkzbmhkxshxcpwpnjzmccjgfdykdncaxjicez
|
|
# sk-bdagppigfxexcofiossccywvcqggbpywjapkdbtqycbgvqpz
|
|
# sk-dvbaktabkdwdpjgxyoozlwnejosjyhdgqwllfeborqahndxs
|
|
|
|
API_KEY_LIST=[
|
|
"sk-kvgfuqeqvpmfsccykyoohheshclcrtvjlnewratvrjpkpbkc",
|
|
"sk-zhnbqnpuumuuvegnvbgoggxafpukbzchpgrugpkobiwkzsar",
|
|
"sk-kzhxlqvqcxlnbdgnpalqnzumkmspepkttkgbophnkqanainw",
|
|
"sk-bzttugqtlskrvguvhckwamdssvgmgnrqpsialpdbskfsyyak",
|
|
"sk-tovmogiablsoeabwgqyvevpcfichyjpuzqdymmvksspdrtqt",
|
|
"sk-wtnjpejveiobtvzsmnuaefqkocsafbfyrtqkkyqardndtxcs",
|
|
"sk-gqdvtrwvzxewnagwsfakrvajtzwgcknatpflkesyqhzjrlal",
|
|
"sk-plivglrkxahodgtgjlaqdjusdoerxspjbcbizaybicarfyuk",
|
|
"sk-gxwaotlyeunxdagmybluhxkberlvohhzteryqgbhbcpztpds",
|
|
"sk-vigugvoqrdqcgkxaiympdmbqtdhpjidylphdcodovfwjpjlf",
|
|
"sk-dgmbountewzxgwcwczyslehpcyejtkhpppibswzcvrjbywey",
|
|
"sk-ksqdvuisvvraeogskmgrwzpolzrfyelqhrajscrylncemyym",
|
|
"sk-vegffsoueyrbtlfbdzfppgtgwouuetoragimogulcncmutnx",
|
|
"sk-moprznmsibswkwnnjwmgssumqhoxdmsxelekkmptseyeussz",
|
|
"sk-kskakjerttqezqqqmdmcbnqssjztrogwqncadgekhmwzjukr",
|
|
"sk-ozwjvlbatnmfjgrxesjkzuzdgpvehmmgswcqctggjxmjgxck",
|
|
"sk-wjmmlmobcayarcvhdeiybhbwdoaacnlltuxyixcwplhedzht",
|
|
"sk-twuvwqxstatdddkobxthzhoddrritsikvnvwuvtqjxwaxhsf",
|
|
"sk-bludnuajavlgdfmelatzsdqhvaxthgagttelsbpviqwiehua",
|
|
"sk-nxxdpmesfzcfzdlnhpsoslajtwbsnzixfjdkuzfjywfktapx",
|
|
"sk-arayylrvatezqgmdbxvxqxydqnmbydbkpkskzxzszmrkkcrq",
|
|
"sk-vxvccjyewpgnnnxpsqkijsawhhpjctcdlfljwfwtguwnmetf",
|
|
"sk-zjwbwyocnuqxfshlpgfzdwlgjjrpewzgvoqwzyhufisidnos",
|
|
"sk-kjxpzjbteiurpzhwjbbjqpjjfoewsahpjtmyqwectdubxhgf",
|
|
"sk-sqdcnhapyzudneipdsuqlfawusrndxqkuwoaoumtonwdnppo",
|
|
"sk-yvyvoiegjrdlgihnxlaaznzdhnvpmfowtwmofomcodaoeaqs",
|
|
"sk-vccwuaomxhjcszjhheipoqqmsnuetasiveombkyrptstesbi",
|
|
"sk-mxbapcczwjsyrictwgigxgcvdgptyfrlynrewqioegqwrggv",
|
|
"sk-dujjzxrknevesbagqgqmuffxsosjoueviubnmodoormlmlzt",
|
|
"sk-rpptsvdeifcnyfkkrwnphgkrlchrqrbkglxrmztdzvfutdor",
|
|
"sk-lsukfggzghmdhtfhqcbmlfqabbtapwpuxnvtwshqqqlaesie",
|
|
"sk-aulumxzhvaladchcwgmsxidtdsvzytbpvzqgfuvcxlwbwcgl",
|
|
"sk-tzdqzroakecvseclcmrbhdnepveatybhhzxfpzxzgirpqcdy",
|
|
"sk-otxxemniwhxkdvroszmmkitswwuykosnqoldrkzdoflqpgvw",
|
|
"sk-zlruqobfdbjebyyvkmehakpcvfgnlfbdlbfrepusazzckbnv",
|
|
"sk-zryimztrlkgvcaiolarhvbcewmhwruhqfcndbylonzlqvdox",
|
|
"sk-rczjqufgdisqplkrmvhaxmdgcboluvxympvzljlreuqeeviq",
|
|
"sk-xfnvcksdgwufsktvmhpqrwpgovsxxtaeehtxnaqjtxmubqzl",
|
|
"sk-gcostftlutooxzsnqefcgyfxqytidvfjpxhbuxppgatwczoq",
|
|
"sk-wwonvjnowbcxmoyoluynnkjwerghspzdulyidskunkordaft",
|
|
"sk-rbuykocecbdoqteveeggwzvrhbvisgaerffexjsnyvjefhdk",
|
|
"sk-qmrkfvvbbfssuoreyvwqawoveyowuvxviqzqknotyweqmuog",
|
|
"sk-nprpuknjmikvoaxnwgyshwwwtnifvixpuqtzkzmcacdnvoib",
|
|
"sk-xanwnicepdxfqrfejzuxjcrhdsglfypkoxlcmmtamrtjkork",
|
|
"sk-lvtdgodiaurqyiwdxtdrgxifguychhccqlqkhqctscvqbfgi",
|
|
"sk-aedlbtlmqcttxwnvlfmxzaysamocamqxjceoyqjfgpcowybw",
|
|
"sk-fahdvndjblyjlizamvwcrxnilsgmbgbvwssxgquhkezgpqne",
|
|
"sk-tzludgttzxvpvwayazdbppbauvathdtccafjrhojpemucgyi",
|
|
"sk-hrbroidbfusidwnsmxenuzljxgdzzxiimlezygxplavnxjik",
|
|
"sk-ylgoiqxmtxeojdnonthxtweungyzldaqarvjxlqyztlvyrff",
|
|
"sk-asuqbqwdhjcqnvtjlwufyrkrwkobnrbmukzarvcctsgjipdp",
|
|
"sk-dpgpymiydutoexgvkajwgahagnfmcqzafwulccudnzvleifz",
|
|
"sk-nbksjgcngsayoumnsdbkcpnqivnvxjenwpzuazzrkhnsgeoo",
|
|
"sk-iaafvpjyqiocgzchbdldbkgcffqniahkcbgoviuevuogulcm",
|
|
"sk-muvjguqeshyimzowqnqgxwpsgujlpkqgrisxsimthtyrpypx",
|
|
"sk-jgybgyayxlwoxeijgrjcneqlyusleohgbliuwpsuhocrjsmk",
|
|
"sk-wzjsmwxcbbpcrqivqfzjwufqqjtlwejtncnvbpeicznkwiuh",
|
|
"sk-izdjicdoyillktsihkiapuvwebisehtlgykozrvzfkgncwsc",
|
|
"sk-fcsfmyivfuojsqsditvobfqprdpeunukycpcfnoxkraqevpx",
|
|
"sk-szyjgyxrcvyxpvzfwgmbxnflxngxvcplitcctsdvvrqjgftk",
|
|
"sk-jzbodthsnvjwbyrnynsxrudtqfnbdbrcxebjwjgajocnzqse",
|
|
"sk-fxepossfzpmccibfwqpkluorzqlbtcaplepeugtfzfsctcbl",
|
|
"sk-ympnflocrkxjrbubsxqdjqwicuyavvvysctlpfhunkcrzxjx",
|
|
"sk-flhqvziknntednkcgjaxlyzzsrfzjhrzrmteqonajpbiinni",
|
|
"sk-xfregpbbquqbxpiobjzanydsjivrjrnbokzxcqtnhxhyghhe",
|
|
"sk-jrdzerhmvrtvzawkksowbgkggkubwfquplmrxbdhespqgtis",
|
|
"sk-jjbpnkbeupsxyclcivbhizcfpfjrppddunbqynyjkqhtmpwu",
|
|
"sk-oqehupcveovkjqqtxypqyifidcdissuyehwrkdwgruoyjkpq",
|
|
"sk-jnnmltwtqwuoyagoogzzeraczmyfxhoairiddgayksqdfnbr",
|
|
"sk-eghuepxnbcollzrjwbzqvbnhiiwagkejaclyhvaodeqgwrog",
|
|
"sk-poszkbjdmamimconjustnrxxqusuzlryxkrzkpronlenrmen",
|
|
"sk-zolvcegarsrwqhwgvwzgtqupodsdmckjiocyvoyldbkusbzc",
|
|
"sk-ywfafulcniaqdgdcsnbtqquaqeuiqlkcnknkaflwxyuemcow",
|
|
"sk-hhedmocgtfpywbbpwamgfkygrahiqsuurntlbqqbmjwfipmm",
|
|
"sk-gzdqfoyvulrqscdpjlwlufdecrsyjpmwpkknuhnjsvtyftox",
|
|
"sk-bkcufidsebujopqqwexwxwpmevrpelmvxzdymncvllcyojce",
|
|
"sk-olabhscekudzkyudypkcjvehwqunagubwdmtppugrjmcptwv",
|
|
"sk-zpdqyocliebhqpkuwvebpgcnfjdkvavdltimllmgkthwnwph",
|
|
"sk-gvhchlfelocjniuydusyhhwacnomxnvucjonzkhtqoplnbcr",
|
|
"sk-lzneagvdxhisodndnxnpkntghpkimjmjsebiqdzaoqzuhbla",
|
|
"sk-xotcfdkigykevngedupitbcatjqppxmcibjtcebyoglykuxz",
|
|
"sk-ufydqsdqnwsegaqwtappzwdyzqnoblyunfvslomnnmykedgk",
|
|
"sk-jwasykftbkyjzdqlwcxuicrwzxsbhttilxfefbrozrznpwlv",
|
|
"sk-xngteojwkxmftyaabjdwwgyoadspsowmcpcqobteutdcfmnr",
|
|
"sk-akzkgniebruqrtuqskvlibkpcxjuazhcatysptkfyqivldfn",
|
|
"sk-vpqkxtmcgkggllexchzysuewyfaoexzasoumxngdplzgwksw",
|
|
"sk-fvcsqdbqmdlwxzjyofrilusqcypbfyczogaqwqrjrwvojmer",
|
|
"sk-htjprscvfgskjtjzpxxxjhyymshagogykpawxekrrfbgftyx",
|
|
]
|
|
|
|
class APIKeyManager:
|
|
"""
|
|
API密钥管理器,用于解析环境变量中的多个API密钥并提供获取接口
|
|
支持密钥轮转使用
|
|
"""
|
|
# 类变量,用于保存单例实例
|
|
_instance = None
|
|
_lock = Lock()
|
|
|
|
# 密钥使用计数和上次使用时间
|
|
_key_usage: Dict[str, Dict] = {}
|
|
# 当前正在使用的密钥索引
|
|
_current_index = 0
|
|
|
|
@classmethod
|
|
def get_instance(cls, env_var_name: str = "OPENAI_API_KEY", separator: str = ";"):
|
|
"""
|
|
获取单例实例
|
|
|
|
Args:
|
|
env_var_name: 环境变量名称,默认为'OPENAI_API_KEY'
|
|
separator: 密钥分隔符,默认为分号
|
|
|
|
Returns:
|
|
APIKeyManager实例
|
|
"""
|
|
if cls._instance is None:
|
|
with cls._lock:
|
|
if cls._instance is None:
|
|
cls._instance = cls(env_var_name, separator)
|
|
return cls._instance
|
|
|
|
@classmethod
|
|
def get_api_key(cls) -> Optional[str]:
|
|
"""
|
|
静态方法:获取一个API密钥,使用轮转策略
|
|
|
|
Returns:
|
|
API密钥,如果没有可用的密钥则返回None
|
|
"""
|
|
instance = cls.get_instance()
|
|
return instance._get_next_api_key()
|
|
|
|
@classmethod
|
|
def get_random_api_key(cls) -> Optional[str]:
|
|
"""
|
|
静态方法:随机获取一个API密钥
|
|
|
|
Returns:
|
|
API密钥,如果没有可用的密钥则返回None
|
|
"""
|
|
instance = cls.get_instance()
|
|
return instance._get_random_api_key()
|
|
|
|
@classmethod
|
|
def get_valid_api_keys(cls) -> List[str]:
|
|
"""
|
|
静态方法:获取有效的API密钥列表
|
|
|
|
Returns:
|
|
"""
|
|
# 验证每一个apikey是否有效,无效则删除并打印日志。地址https://api.siliconflow.cn/v1/
|
|
import requests
|
|
import logging
|
|
|
|
valid_api_keys = []
|
|
url = "https://api.siliconflow.cn/v1/chat/completions"
|
|
headers_template = {
|
|
"Content-Type": "application/json"
|
|
}
|
|
data = {
|
|
"model": "deepseek-ai/DeepSeek-V3",
|
|
"messages": [
|
|
{"role": "user", "content": "ping"}
|
|
],
|
|
"max_tokens": 1
|
|
}
|
|
for key in API_KEY_LIST:
|
|
headers = headers_template.copy()
|
|
headers["Authorization"] = f"Bearer {key}"
|
|
try:
|
|
resp = requests.post(url, headers=headers, json=data, timeout=8)
|
|
if resp.status_code == 200:
|
|
valid_api_keys.append(key)
|
|
else:
|
|
logging.warning(f"API密钥无效(被移除): {key}, 状态码: {resp.status_code}, 响应: {resp.text}")
|
|
except Exception as e:
|
|
logging.warning(f"API密钥验证异常(被移除): {key}, 错误: {e}")
|
|
return valid_api_keys
|
|
|
|
@classmethod
|
|
def count(cls) -> int:
|
|
"""
|
|
静态方法:获取API密钥数量
|
|
|
|
Returns:
|
|
API密钥数量
|
|
"""
|
|
instance = cls.get_instance()
|
|
return len(instance.api_keys)
|
|
|
|
@classmethod
|
|
def get_key_usage_stats(cls, key: str) -> Dict:
|
|
"""
|
|
静态方法:获取API密钥使用统计信息
|
|
|
|
Returns:
|
|
API密钥使用统计信息
|
|
"""
|
|
url = "https://api.siliconflow.cn/v1/user/info"
|
|
|
|
headers = {"Authorization": f"Bearer {key}"}
|
|
|
|
response = requests.request("GET", url, headers=headers)
|
|
|
|
return response.json()
|
|
|
|
def __init__(self, env_var_name: str = "OPENAI_API_KEY", separator: str = ";"):
|
|
"""
|
|
初始化API密钥管理器
|
|
|
|
Args:
|
|
env_var_name: 环境变量名称,默认为'OPENAI_API_KEY'
|
|
separator: 密钥分隔符,默认为分号
|
|
"""
|
|
self.env_var_name = env_var_name
|
|
self.separator = separator
|
|
self.api_keys = self._load_api_keys()
|
|
|
|
# 初始化密钥使用统计
|
|
for key in self.api_keys:
|
|
if key not in self._key_usage:
|
|
self._key_usage[key] = {
|
|
"count": 0,
|
|
"last_used": 0
|
|
}
|
|
|
|
def _load_api_keys(self) -> List[str]:
|
|
"""
|
|
从环境变量加载API密钥
|
|
|
|
Returns:
|
|
API密钥列表
|
|
"""
|
|
# api_keys = []
|
|
# env_value = os.environ.get(self.env_var_name)
|
|
|
|
# if env_value:
|
|
# # 分割环境变量并移除空白字符
|
|
# keys = [key.strip() for key in env_value.split(self.separator)]
|
|
# # 过滤掉空字符串
|
|
# api_keys = [key for key in keys if key]
|
|
|
|
# return api_keys
|
|
return API_KEY_LIST
|
|
|
|
def _get_next_api_key(self) -> Optional[str]:
|
|
"""
|
|
获取下一个API密钥,使用轮转策略
|
|
|
|
Returns:
|
|
API密钥,如果没有可用的密钥则返回None
|
|
"""
|
|
if not self.api_keys:
|
|
return None
|
|
|
|
with self._lock:
|
|
# 轮转到下一个密钥
|
|
self._current_index = (self._current_index + 1) % len(self.api_keys)
|
|
selected_key = self.api_keys[self._current_index]
|
|
|
|
# 更新使用统计
|
|
self._key_usage[selected_key]["count"] += 1
|
|
self._key_usage[selected_key]["last_used"] = time.time()
|
|
|
|
return selected_key
|
|
|
|
def _get_random_api_key(self) -> Optional[str]:
|
|
"""
|
|
随机获取一个API密钥
|
|
|
|
Returns:
|
|
API密钥,如果没有可用的密钥则返回None
|
|
"""
|
|
if not self.api_keys:
|
|
return None
|
|
|
|
with self._lock:
|
|
selected_key = random.choice(self.api_keys)
|
|
|
|
# 更新使用统计
|
|
self._key_usage[selected_key]["count"] += 1
|
|
self._key_usage[selected_key]["last_used"] = time.time()
|
|
|
|
return selected_key
|
|
|
|
def get_all_api_keys(self) -> List[str]:
|
|
"""
|
|
获取所有API密钥
|
|
|
|
Returns:
|
|
API密钥列表
|
|
"""
|
|
return self.api_keys.copy()
|
|
|
|
def is_valid(self) -> bool:
|
|
"""
|
|
检查是否有可用的API密钥
|
|
|
|
Returns:
|
|
如果有可用的API密钥则返回True,否则返回False
|
|
"""
|
|
return len(self.api_keys) > 0
|
|
|
|
def get_usage_stats(self) -> Dict:
|
|
"""
|
|
获取密钥使用统计信息
|
|
|
|
Returns:
|
|
密钥使用统计信息
|
|
"""
|
|
return self._key_usage.copy()
|
|
|
|
|
|
# 使用示例
|
|
if __name__ == "__main__":
|
|
|
|
# 查看总密钥数
|
|
print(f"总共有 {APIKeyManager.count()} 个API密钥")
|
|
|
|
# 获取实例并查看使用统计
|
|
instance = APIKeyManager.get_instance()
|
|
stats = instance.get_usage_stats()
|
|
for key, data in stats.items():
|
|
usage_stats = APIKeyManager.get_key_usage_stats(key)
|
|
print(f"api key:{key}---赠送余额:{usage_stats['data']['balance']}元") |