Update api_usage.py
Browse files- api_usage.py +284 -215
api_usage.py
CHANGED
|
@@ -13,7 +13,8 @@ import asyncio, aiohttp
|
|
| 13 |
import aiohttp
|
| 14 |
|
| 15 |
BASE_URL = 'https://api.openai.com/v1'
|
| 16 |
-
GPT_TYPES = ["gpt-3.5-turbo", "gpt-4", "gpt-4-32k", "gpt-4-32k-0314", "gpt-4o", "gpt-4-turbo"]
|
|
|
|
| 17 |
|
| 18 |
TOKEN_LIMIT_PER_TIER_TURBO = {
|
| 19 |
"free": 40000,
|
|
@@ -42,199 +43,12 @@ RPM_LIMIT_PER_BUILD_TIER_ANT = {
|
|
| 42 |
} # https://docs.anthropic.com/claude/reference/rate-limits
|
| 43 |
|
| 44 |
|
| 45 |
-
def get_headers(key, org_id
|
| 46 |
headers = {'Authorization': f'Bearer {key}'}
|
| 47 |
if org_id:
|
| 48 |
headers["OpenAI-Organization"] = org_id
|
| 49 |
return headers
|
| 50 |
|
| 51 |
-
def get_subscription(key, session, org_list):
|
| 52 |
-
has_gpt4 = False
|
| 53 |
-
has_gpt4_32k = False
|
| 54 |
-
has_gpt4_32k_0314 = False
|
| 55 |
-
default_org = ""
|
| 56 |
-
org_description = []
|
| 57 |
-
org = []
|
| 58 |
-
rpm = []
|
| 59 |
-
tpm = []
|
| 60 |
-
quota = []
|
| 61 |
-
list_models = []
|
| 62 |
-
list_models_avai = set()
|
| 63 |
-
|
| 64 |
-
for org_in in org_list:
|
| 65 |
-
if len(org_list) < 2: # mismatch_organization
|
| 66 |
-
headers = get_headers(key)
|
| 67 |
-
available_models = get_models(session, key)
|
| 68 |
-
else:
|
| 69 |
-
headers = get_headers(key, org_in['id'])
|
| 70 |
-
available_models = get_models(session, key, org_in['id'])
|
| 71 |
-
if org_in['id']:
|
| 72 |
-
if org_in['is_default']:
|
| 73 |
-
default_org = org_in['name']
|
| 74 |
-
org_description.append(f"{org_in['description']} (Created: {datetime.utcfromtimestamp(org_in['created'])} UTC" + (", personal)" if org_in['personal'] else ")"))
|
| 75 |
-
if 'No perm' in available_models:
|
| 76 |
-
available_models.extend(GPT_TYPES)
|
| 77 |
-
has_gpt4_32k = True if GPT_TYPES[2] in available_models else False
|
| 78 |
-
has_gpt4_32k_0314 = True if GPT_TYPES[3] in available_models else False
|
| 79 |
-
has_gpt4 = True if GPT_TYPES[1] in available_models else False
|
| 80 |
-
|
| 81 |
-
if has_gpt4_32k_0314 or has_gpt4_32k:
|
| 82 |
-
if org_in['id']:
|
| 83 |
-
org.append(f"{org_in['id']} ({org_in['name']}, {org_in['title']}, {org_in['role']})")
|
| 84 |
-
if has_gpt4_32k:
|
| 85 |
-
list_models_avai.update(GPT_TYPES)
|
| 86 |
-
if 'No perm' in available_models:
|
| 87 |
-
status_formated = format_status(GPT_TYPES, session, headers)
|
| 88 |
-
else:
|
| 89 |
-
status_formated = format_status([GPT_TYPES[2], GPT_TYPES[4], GPT_TYPES[5], GPT_TYPES[1], GPT_TYPES[0]], session, headers)
|
| 90 |
-
rpm.append(status_formated[0])
|
| 91 |
-
tpm.append(status_formated[1])
|
| 92 |
-
quota.append(status_formated[2])
|
| 93 |
-
if 'No perm' in available_models:
|
| 94 |
-
lst_string = ""
|
| 95 |
-
length = len(status_formated[3])
|
| 96 |
-
count = 1
|
| 97 |
-
for k, v in status_formated[3].items():
|
| 98 |
-
if v:
|
| 99 |
-
if count < length:
|
| 100 |
-
lst_string += f'{k}, '
|
| 101 |
-
continue
|
| 102 |
-
else:
|
| 103 |
-
lst_string += f' {k} '
|
| 104 |
-
if v == False:
|
| 105 |
-
list_models_avai.remove(k)
|
| 106 |
-
if k == GPT_TYPES[2]:
|
| 107 |
-
has_gpt4_32k = False
|
| 108 |
-
elif k == GPT_TYPES[1]:
|
| 109 |
-
has_gpt4 = False
|
| 110 |
-
elif k == GPT_TYPES[0]:
|
| 111 |
-
has_35 = False
|
| 112 |
-
elif k == GPT_TYPES[4]:
|
| 113 |
-
has_4o = False
|
| 114 |
-
count += 1
|
| 115 |
-
lst_string += '(No get model permission)'
|
| 116 |
-
#list_models.append(f"gpt-4-32k, gpt-4o, gpt-4-turbo, gpt-4, gpt-3.5-turbo (No get model permission)")
|
| 117 |
-
list_models.append(lst_string)
|
| 118 |
-
else:
|
| 119 |
-
list_models.append(f"gpt-4-32k, gpt-4o, gpt-4-turbo, gpt-4, gpt-3.5-turbo ({len(available_models)} total)")
|
| 120 |
-
else:
|
| 121 |
-
list_models_avai.update([GPT_TYPES[3], GPT_TYPES[1], GPT_TYPES[0]])
|
| 122 |
-
status_formated = format_status([GPT_TYPES[3], GPT_TYPES[4], GPT_TYPES[5], GPT_TYPES[1], GPT_TYPES[0]], session, headers)
|
| 123 |
-
rpm.append(status_formated[0])
|
| 124 |
-
tpm.append(status_formated[1])
|
| 125 |
-
quota.append(status_formated[2])
|
| 126 |
-
list_models.append(f"gpt-4-32k-0314, gpt-4o, gpt-4-turbo, gpt-4, gpt-3.5-turbo ({len(available_models)} total)")
|
| 127 |
-
|
| 128 |
-
elif has_gpt4:
|
| 129 |
-
if org_in['id']:
|
| 130 |
-
org.append(f"{org_in['id']} ({org_in['name']}, {org_in['title']}, {org_in['role']})")
|
| 131 |
-
list_models_avai.update([GPT_TYPES[1], GPT_TYPES[0]])
|
| 132 |
-
status_formated = format_status([GPT_TYPES[4], GPT_TYPES[5], GPT_TYPES[1], GPT_TYPES[0]], session, headers)
|
| 133 |
-
rpm.append(status_formated[0])
|
| 134 |
-
tpm.append(status_formated[1])
|
| 135 |
-
quota.append(status_formated[2])
|
| 136 |
-
list_models.append(f"gpt-4o, gpt-4-turbo, gpt-4, gpt-3.5-turbo ({len(available_models)} total)")
|
| 137 |
-
|
| 138 |
-
else:
|
| 139 |
-
if org_in['id']:
|
| 140 |
-
org.append(f"{org_in['id']} ({org_in['name']}, {org_in['title']}, {org_in['role']})")
|
| 141 |
-
list_models_avai.update([GPT_TYPES[0]])
|
| 142 |
-
status_formated = format_status([GPT_TYPES[0]], session, headers)
|
| 143 |
-
rpm.append(status_formated[0])
|
| 144 |
-
tpm.append(status_formated[1])
|
| 145 |
-
quota.append(status_formated[2])
|
| 146 |
-
list_models.append(f"gpt-3.5-turbo ({len(available_models)} total)")
|
| 147 |
-
|
| 148 |
-
return {"has_gpt4_32k": True if GPT_TYPES[2] in list_models_avai else False,
|
| 149 |
-
"has_gpt4": True if GPT_TYPES[1] in list_models_avai else False,
|
| 150 |
-
"default_org": default_org,
|
| 151 |
-
"organization": [o for o in org],
|
| 152 |
-
"org_description": org_description,
|
| 153 |
-
"models": list_models,
|
| 154 |
-
"rpm": rpm,
|
| 155 |
-
"tpm": tpm,
|
| 156 |
-
"quota": quota}
|
| 157 |
-
|
| 158 |
-
def send_oai_completions(oai_stuff):
|
| 159 |
-
session = oai_stuff[0]
|
| 160 |
-
headers = oai_stuff[1]
|
| 161 |
-
model = oai_stuff[2]
|
| 162 |
-
model_status = False
|
| 163 |
-
try:
|
| 164 |
-
req_body = {"model": model, "max_tokens": 1}
|
| 165 |
-
rpm_string = ""
|
| 166 |
-
tpm_string = ""
|
| 167 |
-
quota_string = ""
|
| 168 |
-
r = session.post(f"{BASE_URL}/chat/completions", headers=headers, json=req_body, timeout=10)
|
| 169 |
-
result = r.json()
|
| 170 |
-
if "error" in result:
|
| 171 |
-
e = result.get("error", {}).get("code", "")
|
| 172 |
-
if e == None or e == 'missing_required_parameter':
|
| 173 |
-
rpm_num = int(r.headers.get("x-ratelimit-limit-requests", 0))
|
| 174 |
-
model_status = True
|
| 175 |
-
tpm_num = int(r.headers.get('x-ratelimit-limit-tokens', 0))
|
| 176 |
-
tpm_left = int(r.headers.get('x-ratelimit-remaining-tokens', 0))
|
| 177 |
-
_rpm = '{:,}'.format(rpm_num).replace(',', ' ')
|
| 178 |
-
_tpm = '{:,}'.format(tpm_num).replace(',', ' ')
|
| 179 |
-
_tpm_left = '{:,}'.format(tpm_left).replace(',', ' ')
|
| 180 |
-
rpm_string = f"{_rpm} ({model})"
|
| 181 |
-
#tpm_string = f"{_tpm} ({_tpm_left} left, {model})"
|
| 182 |
-
tpm_string = f"{_tpm} ({model})"
|
| 183 |
-
dictCount = 0
|
| 184 |
-
dictLength = len(TOKEN_LIMIT_PER_TIER_GPT4)
|
| 185 |
-
|
| 186 |
-
# Check if gpt-4 has custom tpm (600k for example), if not, proceed with 3turbo's tpm
|
| 187 |
-
if model == GPT_TYPES[1]:
|
| 188 |
-
for k, v in TOKEN_LIMIT_PER_TIER_GPT4.items():
|
| 189 |
-
if tpm_num == v:
|
| 190 |
-
break
|
| 191 |
-
else:
|
| 192 |
-
dictCount+=1
|
| 193 |
-
if dictCount == dictLength:
|
| 194 |
-
quota_string = "yes | custom-tier"
|
| 195 |
-
elif model == GPT_TYPES[0] and quota_string == "":
|
| 196 |
-
quota_string = check_key_tier(rpm_num, tpm_num, TOKEN_LIMIT_PER_TIER_TURBO, headers)
|
| 197 |
-
else:
|
| 198 |
-
rpm_string = f"0 ({model})"
|
| 199 |
-
tpm_string = f"0 ({model})"
|
| 200 |
-
quota_string = e
|
| 201 |
-
return rpm_string, tpm_string, quota_string, model, model_status
|
| 202 |
-
except Exception as e:
|
| 203 |
-
#print(e)
|
| 204 |
-
return "", "", "", model, model_status
|
| 205 |
-
|
| 206 |
-
def format_status(list_models_avai, session, headers):
|
| 207 |
-
rpm = []
|
| 208 |
-
tpm = []
|
| 209 |
-
model_status = {}
|
| 210 |
-
quota = ""
|
| 211 |
-
args = [(session, headers, model) for model in list_models_avai]
|
| 212 |
-
with concurrent.futures.ThreadPoolExecutor() as executer:
|
| 213 |
-
for result in executer.map(send_oai_completions, args):
|
| 214 |
-
rpm.append(result[0])
|
| 215 |
-
tpm.append(result[1])
|
| 216 |
-
model_status[result[3]] = result[4]
|
| 217 |
-
if result[2]:
|
| 218 |
-
if quota == 'yes | custom-tier':
|
| 219 |
-
continue
|
| 220 |
-
else:
|
| 221 |
-
quota = result[2]
|
| 222 |
-
rpm_str = ""
|
| 223 |
-
tpm_str = ""
|
| 224 |
-
for i in range(len(rpm)):
|
| 225 |
-
rpm_str += rpm[i] + (" | " if i < len(rpm)-1 else "")
|
| 226 |
-
tpm_str += tpm[i] + (" | " if i < len(rpm)-1 else "")
|
| 227 |
-
return rpm_str, tpm_str, quota, model_status
|
| 228 |
-
|
| 229 |
-
def check_key_tier(rpm, tpm, dict, headers):
|
| 230 |
-
dictItemsCount = len(dict)
|
| 231 |
-
dictCount = 0
|
| 232 |
-
for k, v in dict.items():
|
| 233 |
-
if tpm == v:
|
| 234 |
-
return f"yes | {k}"
|
| 235 |
-
dictCount+=1
|
| 236 |
-
if (dictCount == dictItemsCount):
|
| 237 |
-
return "yes | custom-tier"
|
| 238 |
|
| 239 |
def get_orgs(session, key):
|
| 240 |
headers=get_headers(key)
|
|
@@ -242,33 +56,205 @@ def get_orgs(session, key):
|
|
| 242 |
rq = session.get(f"{BASE_URL}/organizations", headers=headers, timeout=10)
|
| 243 |
return 200, rq.json()['data']
|
| 244 |
except:
|
| 245 |
-
if rq.status_code == 403:
|
| 246 |
return 403, rq.json()['error']['message']
|
| 247 |
else:
|
| 248 |
return False, False
|
| 249 |
-
|
| 250 |
-
def
|
| 251 |
-
|
| 252 |
-
headers = get_headers(key, org)
|
| 253 |
-
else:
|
| 254 |
-
headers = get_headers(key)
|
| 255 |
-
|
| 256 |
try:
|
| 257 |
-
rq = session.get(f"{BASE_URL}/
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
|
| 261 |
-
|
| 262 |
except:
|
| 263 |
-
|
| 264 |
-
|
| 265 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
def check_key_availability(session, key):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 267 |
try:
|
| 268 |
-
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 272 |
|
| 273 |
async def fetch_ant(async_session, json_data):
|
| 274 |
url = 'https://api.anthropic.com/v1/messages'
|
|
@@ -347,8 +333,17 @@ async def check_key_ant_availability(key, claude_model):
|
|
| 347 |
tpm = ""
|
| 348 |
tpm_left = ""
|
| 349 |
tier = ""
|
| 350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
async with aiohttp.ClientSession(headers=headers) as async_session:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 352 |
async with async_session.post(url=url, json=json_data) as response:
|
| 353 |
result = await response.json()
|
| 354 |
if response.status == 200:
|
|
@@ -356,15 +351,19 @@ async def check_key_ant_availability(key, claude_model):
|
|
| 356 |
rpm_left = response.headers.get('anthropic-ratelimit-requests-remaining', '')
|
| 357 |
tpm = response.headers.get('anthropic-ratelimit-tokens-limit', '')
|
| 358 |
tpm_left = response.headers.get('anthropic-ratelimit-tokens-remaining', '')
|
|
|
|
|
|
|
|
|
|
|
|
|
| 359 |
tier = check_ant_tier(rpm)
|
| 360 |
msg = result.get('content', [''])[0].get('text', '')
|
| 361 |
-
return True, "Working", msg, rpm, rpm_left, tpm, tpm_left, tier
|
| 362 |
else:
|
| 363 |
#err_type = result.get('error', '').get('type', '')
|
| 364 |
err_msg = result.get('error', '').get('message', '')
|
| 365 |
if response.status == 401:
|
| 366 |
-
return False, f'Error: {response.status}', err_msg, rpm, rpm_left, tpm, tpm_left, tier
|
| 367 |
-
return True, f'Error: {response.status}', err_msg, rpm, rpm_left, tpm, tpm_left, tier
|
| 368 |
|
| 369 |
def check_key_gemini_availability(key):
|
| 370 |
avai = False
|
|
@@ -642,7 +641,7 @@ def is_model_working(form_info, model_info):
|
|
| 642 |
return model_info['agreementAvailability']['errorMessage']
|
| 643 |
return "No"
|
| 644 |
except:
|
| 645 |
-
return "
|
| 646 |
|
| 647 |
async def get_model_status(session, key, secret, region, model_name, form_info):
|
| 648 |
model_info = await bedrock_model_available(session, key, secret, region, f"anthropic.{model_name}")
|
|
@@ -686,7 +685,7 @@ async def check_bedrock_claude_status(session, key, secret):
|
|
| 686 |
if region and model_name:
|
| 687 |
if msg == "Maybe":
|
| 688 |
invoke_info = await send_signed_request_bedrock(session, payload, f"anthropic.{model_name}", key, secret, region)
|
| 689 |
-
if 'messages.0' in invoke_info.get('message') or 'many requests' in invoke_info.get('message'):
|
| 690 |
models[model_name].append(f'{region}')
|
| 691 |
else:
|
| 692 |
models[model_name].append(region)
|
|
@@ -883,6 +882,76 @@ def check_elevenlabs_status(key):
|
|
| 883 |
else:
|
| 884 |
return False, user_info[1], ""
|
| 885 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 886 |
if __name__ == "__main__":
|
| 887 |
key = os.getenv("OPENAI_API_KEY")
|
| 888 |
key_ant = os.getenv("ANTHROPIC_API_KEY")
|
|
|
|
| 13 |
import aiohttp
|
| 14 |
|
| 15 |
BASE_URL = 'https://api.openai.com/v1'
|
| 16 |
+
GPT_TYPES = ["gpt-3.5-turbo", "gpt-4", "gpt-4-32k", "gpt-4-32k-0314", "gpt-4o", "gpt-4-turbo", "chatgpt-4o-latest" ]
|
| 17 |
+
GPT_TYPES_ORDER = ["gpt-4-32k", "gpt-4-32k-0314", "chatgpt-4o-latest", "gpt-4o", "gpt-4-turbo", "gpt-4", "gpt-3.5-turbo"]
|
| 18 |
|
| 19 |
TOKEN_LIMIT_PER_TIER_TURBO = {
|
| 20 |
"free": 40000,
|
|
|
|
| 43 |
} # https://docs.anthropic.com/claude/reference/rate-limits
|
| 44 |
|
| 45 |
|
| 46 |
+
def get_headers(key, org_id=None):
|
| 47 |
headers = {'Authorization': f'Bearer {key}'}
|
| 48 |
if org_id:
|
| 49 |
headers["OpenAI-Organization"] = org_id
|
| 50 |
return headers
|
| 51 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
|
| 53 |
def get_orgs(session, key):
|
| 54 |
headers=get_headers(key)
|
|
|
|
| 56 |
rq = session.get(f"{BASE_URL}/organizations", headers=headers, timeout=10)
|
| 57 |
return 200, rq.json()['data']
|
| 58 |
except:
|
| 59 |
+
if rq.status_code == 403 or (rq.status_code == 401 and 'invalid_request_error' in f'{rq.text}'):
|
| 60 |
return 403, rq.json()['error']['message']
|
| 61 |
else:
|
| 62 |
return False, False
|
| 63 |
+
|
| 64 |
+
def get_orgs_me(session, key):
|
| 65 |
+
headers=get_headers(key)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
try:
|
| 67 |
+
rq = session.get(f"{BASE_URL}/me", headers=headers, timeout=10)
|
| 68 |
+
if rq.status_code == 200:
|
| 69 |
+
return 200, rq.json()['orgs']['data']
|
| 70 |
+
else:
|
| 71 |
+
return rq.status_code, ""
|
| 72 |
except:
|
| 73 |
+
return False, rq.json()['error']['message']
|
| 74 |
+
|
| 75 |
+
def get_models(session, key, org_id=None):
|
| 76 |
+
headers = get_headers(key, org_id)
|
| 77 |
+
try:
|
| 78 |
+
response = session.get(f"{BASE_URL}/models", headers=headers, timeout=10)
|
| 79 |
+
response.raise_for_status()
|
| 80 |
+
all_models = response.json().get("data", [])
|
| 81 |
+
available_models = [model["id"] for model in all_models]
|
| 82 |
+
return available_models, all_models
|
| 83 |
+
except requests.exceptions.RequestException:
|
| 84 |
+
if response.status_code == 403:
|
| 85 |
+
return ['No perm'], []
|
| 86 |
+
return [], []
|
| 87 |
+
|
| 88 |
+
|
| 89 |
def check_key_availability(session, key):
|
| 90 |
+
return get_orgs(session, key)
|
| 91 |
+
|
| 92 |
+
def get_subscription(key, session, org_data):
|
| 93 |
+
default_org = ""
|
| 94 |
+
org_description = []
|
| 95 |
+
organizations = []
|
| 96 |
+
rpm_list = []
|
| 97 |
+
tpm_list = []
|
| 98 |
+
quota_list = []
|
| 99 |
+
models_list = []
|
| 100 |
+
int_models = []
|
| 101 |
+
all_models = []
|
| 102 |
+
has_gpt4 = False
|
| 103 |
+
has_gpt4_32k = False
|
| 104 |
+
|
| 105 |
+
if isinstance(org_data, str):
|
| 106 |
+
organizations.append(org_data)
|
| 107 |
+
org_list = [{"id": ""}]
|
| 108 |
+
else:
|
| 109 |
+
org_list = org_data
|
| 110 |
+
#print(org_list)
|
| 111 |
+
for org in org_list:
|
| 112 |
+
org_id = org.get('id')
|
| 113 |
+
headers = get_headers(key, org_id)
|
| 114 |
+
all_available_models_info = get_models(session, key, org_id)
|
| 115 |
+
all_available_models = all_available_models_info[0]
|
| 116 |
+
available_models = [model for model in all_available_models if model in GPT_TYPES]
|
| 117 |
+
if 'No perm' in available_models:
|
| 118 |
+
available_models = GPT_TYPES
|
| 119 |
+
|
| 120 |
+
if org.get('is_default'):
|
| 121 |
+
default_org = org.get('name', '')
|
| 122 |
+
|
| 123 |
+
if org_id:
|
| 124 |
+
organizations.append(f"{org_id} ({org.get('name')}, {org.get('title')}, {org.get('role')})")
|
| 125 |
+
org_description.append(f"{org.get('description')} (Created: {datetime.utcfromtimestamp(org.get('created'))} UTC"
|
| 126 |
+
+ (", personal)" if org.get('personal') else ")"))
|
| 127 |
+
|
| 128 |
+
status = format_status(available_models, session, headers)
|
| 129 |
+
rpm_list.append(" | ".join(status["rpm"]))
|
| 130 |
+
tpm_list.append(" | ".join(status["tpm"]))
|
| 131 |
+
|
| 132 |
+
quota = determine_quota_for_org(status)
|
| 133 |
+
quota_list.append(quota)
|
| 134 |
+
|
| 135 |
+
models_list.append(", ".join(status["models"]) + f" ({len(all_available_models)} total)")
|
| 136 |
+
all_models.append(all_available_models)
|
| 137 |
+
|
| 138 |
+
has_gpt4 = has_gpt4 or GPT_TYPES[1] in available_models
|
| 139 |
+
has_gpt4_32k = has_gpt4_32k or GPT_TYPES[2] in available_models
|
| 140 |
+
|
| 141 |
+
return {
|
| 142 |
+
"has_gpt4": has_gpt4,
|
| 143 |
+
"has_gpt4_32k": has_gpt4_32k,
|
| 144 |
+
"default_org": default_org,
|
| 145 |
+
"organization": organizations,
|
| 146 |
+
"org_description": org_description,
|
| 147 |
+
"models": models_list,
|
| 148 |
+
"rpm": rpm_list,
|
| 149 |
+
"tpm": tpm_list,
|
| 150 |
+
"quota": quota_list,
|
| 151 |
+
"all_models": all_models
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
def determine_quota_for_org(status):
|
| 156 |
+
for model, quota in zip(status["models"], status["quota"]):
|
| 157 |
+
if model == "gpt-4":
|
| 158 |
+
if quota == "custom-tier":
|
| 159 |
+
return quota
|
| 160 |
+
|
| 161 |
+
for model, quota in zip(status["models"], status["quota"]):
|
| 162 |
+
if model == "gpt-3.5-turbo":
|
| 163 |
+
return quota
|
| 164 |
+
|
| 165 |
+
for quota in status["quota"]:
|
| 166 |
+
if quota not in ["unknown", "custom-tier"]:
|
| 167 |
+
return quota
|
| 168 |
+
|
| 169 |
+
return "unknown"
|
| 170 |
+
|
| 171 |
+
def format_status(models, session, headers):
|
| 172 |
+
rpm = []
|
| 173 |
+
tpm = []
|
| 174 |
+
quota = []
|
| 175 |
+
model_status = {}
|
| 176 |
+
|
| 177 |
+
args = [(session, headers, model) for model in models]
|
| 178 |
+
|
| 179 |
+
with concurrent.futures.ThreadPoolExecutor() as executor:
|
| 180 |
+
results = executor.map(lambda x: send_oai_completions(*x), args)
|
| 181 |
+
|
| 182 |
+
model_results = {result["model"]: result for result in results}
|
| 183 |
+
|
| 184 |
+
sorted_models = [model for model in GPT_TYPES_ORDER if model in model_results]
|
| 185 |
+
|
| 186 |
+
for model in sorted_models:
|
| 187 |
+
result = model_results[model]
|
| 188 |
+
rpm.append(result["rpm"])
|
| 189 |
+
tpm.append(result["tpm"])
|
| 190 |
+
quota.append(result["quota"])
|
| 191 |
+
model_status[model] = result["status"]
|
| 192 |
+
|
| 193 |
+
return {
|
| 194 |
+
"rpm": rpm,
|
| 195 |
+
"tpm": tpm,
|
| 196 |
+
"quota": quota,
|
| 197 |
+
"models": sorted_models,
|
| 198 |
+
"model_status": model_status
|
| 199 |
+
}
|
| 200 |
+
|
| 201 |
+
def send_oai_completions(session, headers, model):
|
| 202 |
try:
|
| 203 |
+
response = session.post(
|
| 204 |
+
f"{BASE_URL}/chat/completions",
|
| 205 |
+
headers=headers,
|
| 206 |
+
json={"model": model, "max_tokens": 1},
|
| 207 |
+
timeout=10
|
| 208 |
+
)
|
| 209 |
+
|
| 210 |
+
result = response.json()
|
| 211 |
+
rpm = int(response.headers.get("x-ratelimit-limit-requests", 0))
|
| 212 |
+
tpm = int(response.headers.get("x-ratelimit-limit-tokens", 0))
|
| 213 |
+
quota_string = ""
|
| 214 |
+
|
| 215 |
+
if "error" in result:
|
| 216 |
+
error_code = result.get("error", {}).get("code", "")
|
| 217 |
+
if error_code in [None, "missing_required_parameter"]:
|
| 218 |
+
quota_string = check_tier(tpm, TOKEN_LIMIT_PER_TIER_GPT4 if model == "gpt-4" else TOKEN_LIMIT_PER_TIER_TURBO)
|
| 219 |
+
return {
|
| 220 |
+
"rpm": f"{rpm:,} ({model})",
|
| 221 |
+
"tpm": f"{tpm:,} ({model})",
|
| 222 |
+
"quota": quota_string,
|
| 223 |
+
"model": model,
|
| 224 |
+
"status": True
|
| 225 |
+
}
|
| 226 |
+
else:
|
| 227 |
+
return {
|
| 228 |
+
"rpm": f"0 ({model})",
|
| 229 |
+
"tpm": f"0 ({model})",
|
| 230 |
+
"quota": error_code,
|
| 231 |
+
"model": model,
|
| 232 |
+
"status": False
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
quota_string = check_tier(tpm, TOKEN_LIMIT_PER_TIER_GPT4 if model == "gpt-4" else TOKEN_LIMIT_PER_TIER_TURBO)
|
| 236 |
+
return {
|
| 237 |
+
"rpm": f"{rpm:,} ({model})",
|
| 238 |
+
"tpm": f"{tpm:,} ({model})",
|
| 239 |
+
"quota": quota_string,
|
| 240 |
+
"model": model,
|
| 241 |
+
"status": True
|
| 242 |
+
}
|
| 243 |
+
|
| 244 |
+
except requests.exceptions.RequestException:
|
| 245 |
+
return {
|
| 246 |
+
"rpm": "0",
|
| 247 |
+
"tpm": "0",
|
| 248 |
+
"quota": "request_failed",
|
| 249 |
+
"model": model,
|
| 250 |
+
"status": False
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
def check_tier(tpm, token_limits):
|
| 254 |
+
for tier, limit in token_limits.items():
|
| 255 |
+
if tpm == limit:
|
| 256 |
+
return tier
|
| 257 |
+
return "custom-tier"
|
| 258 |
|
| 259 |
async def fetch_ant(async_session, json_data):
|
| 260 |
url = 'https://api.anthropic.com/v1/messages'
|
|
|
|
| 333 |
tpm = ""
|
| 334 |
tpm_left = ""
|
| 335 |
tier = ""
|
| 336 |
+
tpm_input = ""
|
| 337 |
+
tpm_input_left = ""
|
| 338 |
+
tpm_output = ""
|
| 339 |
+
tpm_output_left = ""
|
| 340 |
+
models = ""
|
| 341 |
async with aiohttp.ClientSession(headers=headers) as async_session:
|
| 342 |
+
async with async_session.get(url='https://api.anthropic.com/v1/models') as m_response:
|
| 343 |
+
if m_response.status == 200:
|
| 344 |
+
models_info = await m_response.json()
|
| 345 |
+
models = [model['id'] for model in models_info['data']]
|
| 346 |
+
|
| 347 |
async with async_session.post(url=url, json=json_data) as response:
|
| 348 |
result = await response.json()
|
| 349 |
if response.status == 200:
|
|
|
|
| 351 |
rpm_left = response.headers.get('anthropic-ratelimit-requests-remaining', '')
|
| 352 |
tpm = response.headers.get('anthropic-ratelimit-tokens-limit', '')
|
| 353 |
tpm_left = response.headers.get('anthropic-ratelimit-tokens-remaining', '')
|
| 354 |
+
tpm_input = response.headers.get('anthropic-ratelimit-input-tokens-limit', '')
|
| 355 |
+
tpm_input_left = response.headers.get('anthropic-ratelimit-input-tokens-remaining', '')
|
| 356 |
+
tpm_output = response.headers.get('anthropic-ratelimit-output-tokens-limit', '')
|
| 357 |
+
tpm_output_left = response.headers.get('anthropic-ratelimit-output-tokens-remaining', '')
|
| 358 |
tier = check_ant_tier(rpm)
|
| 359 |
msg = result.get('content', [''])[0].get('text', '')
|
| 360 |
+
return True, "Working", msg, rpm, rpm_left, tpm, tpm_left, tier, tpm_input, tpm_input_left, tpm_output, tpm_output_left, models
|
| 361 |
else:
|
| 362 |
#err_type = result.get('error', '').get('type', '')
|
| 363 |
err_msg = result.get('error', '').get('message', '')
|
| 364 |
if response.status == 401:
|
| 365 |
+
return False, f'Error: {response.status}', err_msg, rpm, rpm_left, tpm, tpm_left, tier, tpm_input, tpm_input_left, tpm_output, tpm_output_left, models
|
| 366 |
+
return True, f'Error: {response.status}', err_msg, rpm, rpm_left, tpm, tpm_left, tier, tpm_input, tpm_input_left, tpm_output, tpm_output_left, models
|
| 367 |
|
| 368 |
def check_key_gemini_availability(key):
|
| 369 |
avai = False
|
|
|
|
| 641 |
return model_info['agreementAvailability']['errorMessage']
|
| 642 |
return "No"
|
| 643 |
except:
|
| 644 |
+
return "Maybe"
|
| 645 |
|
| 646 |
async def get_model_status(session, key, secret, region, model_name, form_info):
|
| 647 |
model_info = await bedrock_model_available(session, key, secret, region, f"anthropic.{model_name}")
|
|
|
|
| 685 |
if region and model_name:
|
| 686 |
if msg == "Maybe":
|
| 687 |
invoke_info = await send_signed_request_bedrock(session, payload, f"anthropic.{model_name}", key, secret, region)
|
| 688 |
+
if 'messages.0' in invoke_info.get('message') or 'many requests' in invoke_info.get('message') or 'equal to 1' in invoke_info.get('message'):
|
| 689 |
models[model_name].append(f'{region}')
|
| 690 |
else:
|
| 691 |
models[model_name].append(region)
|
|
|
|
| 882 |
else:
|
| 883 |
return False, user_info[1], ""
|
| 884 |
|
| 885 |
+
def check_xai_status(key):
|
| 886 |
+
url = 'https://api.x.ai/v1/'
|
| 887 |
+
headers = {"authorization": f"Bearer {key}"}
|
| 888 |
+
response = requests.get(url+"api-key", headers=headers)
|
| 889 |
+
if response.status_code == 200:
|
| 890 |
+
response_models = requests.get(url+"models", headers=headers)
|
| 891 |
+
models = response_models.json()
|
| 892 |
+
if 'data' in models:
|
| 893 |
+
return True, response.json(), models['data']
|
| 894 |
+
return True, response.json(), models
|
| 895 |
+
else:
|
| 896 |
+
return False, response.json(), ""
|
| 897 |
+
|
| 898 |
+
def check_stripe_status(key):
|
| 899 |
+
response = requests.get('https://api.stripe.com/v1/balance', auth=(key, ''))
|
| 900 |
+
|
| 901 |
+
if response.status_code == 200:
|
| 902 |
+
return True, response.json()
|
| 903 |
+
else:
|
| 904 |
+
return False, response.json()
|
| 905 |
+
|
| 906 |
+
def check_stability_info(url, headers):
|
| 907 |
+
response = requests.get(url=url, headers=headers)
|
| 908 |
+
if response.status_code == 200:
|
| 909 |
+
return True, response.json()
|
| 910 |
+
else:
|
| 911 |
+
return False, response.json()
|
| 912 |
+
|
| 913 |
+
def check_stability_status(key):
|
| 914 |
+
headers = {"Authorization": f"Bearer {key}"}
|
| 915 |
+
|
| 916 |
+
status, account = check_stability_info('https://api.stability.ai/v1/user/account', headers)
|
| 917 |
+
|
| 918 |
+
if 'Incorrect API key' in f'{account}':
|
| 919 |
+
return False, account, "", ""
|
| 920 |
+
|
| 921 |
+
_, models = check_stability_info('https://api.stability.ai/v1/engines/list', headers)
|
| 922 |
+
_, credit = check_stability_info('https://api.stability.ai/v1/user/balance', headers)
|
| 923 |
+
|
| 924 |
+
return True, account, models, credit
|
| 925 |
+
|
| 926 |
+
def check_deepseek_balance(key):
|
| 927 |
+
url = 'https://api.deepseek.com/user/balance'
|
| 928 |
+
headers = {"Authorization": f"Bearer {key}"}
|
| 929 |
+
response = requests.get(url, headers=headers)
|
| 930 |
+
|
| 931 |
+
if response.status_code == 200:
|
| 932 |
+
return response.json()
|
| 933 |
+
else:
|
| 934 |
+
return ""
|
| 935 |
+
|
| 936 |
+
def check_deepseek_models(key):
|
| 937 |
+
url = 'https://api.deepseek.com/models'
|
| 938 |
+
headers = {"Authorization": f"Bearer {key}"}
|
| 939 |
+
response = requests.get(url, headers=headers)
|
| 940 |
+
|
| 941 |
+
if response.status_code == 200:
|
| 942 |
+
return True, response.json()['data']
|
| 943 |
+
else:
|
| 944 |
+
return False, response.json()
|
| 945 |
+
|
| 946 |
+
def check_deepseek_status(key):
|
| 947 |
+
status, models = check_deepseek_models(key)
|
| 948 |
+
if not status and 'no such user' in f'{models}':
|
| 949 |
+
return False, models, ""
|
| 950 |
+
|
| 951 |
+
balance_info = check_deepseek_balance(key)
|
| 952 |
+
|
| 953 |
+
return True, models, balance_info
|
| 954 |
+
|
| 955 |
if __name__ == "__main__":
|
| 956 |
key = os.getenv("OPENAI_API_KEY")
|
| 957 |
key_ant = os.getenv("ANTHROPIC_API_KEY")
|