From 64c0ad59792a60a9e07bf66f6f28d7d18643bc1f Mon Sep 17 00:00:00 2001 From: based Date: Wed, 20 Mar 2024 00:52:55 +1000 Subject: [PATCH] added 11labs support + detect dalle deployments on azure --- APIKey.py | 11 ++++++++++- Azure.py | 6 +++++- ElevenLabs.py | 42 ++++++++++++++++++++++++++++++++++++++++++ README.md | 5 +++-- main.py | 40 ++++++++++++++++++++++++++++++++-------- 5 files changed, 92 insertions(+), 12 deletions(-) create mode 100644 ElevenLabs.py diff --git a/APIKey.py b/APIKey.py index 47fad1f..da7d9e9 100644 --- a/APIKey.py +++ b/APIKey.py @@ -43,6 +43,7 @@ class APIKey: self.model = "" self.deployments = [] self.unfiltered = False + self.dalle_deployments = "" elif provider == Provider.VERTEXAI: self.project_id = "" @@ -61,6 +62,13 @@ class APIKey: self.limit_reached = False self.bought_credits = False + elif provider == Provider.ELEVENLABS: + self.characters_left = 0 + self.usage = "" + self.tier = "" + self.unlimited = False + self.pro_voice_limit = 0 + def clone(self): cloned_key = APIKey(self.provider, self.api_key) cloned_key.__dict__ = self.__dict__.copy() @@ -76,4 +84,5 @@ class Provider(Enum): AZURE = 6 VERTEXAI = 7 MISTRAL = 8 - OPENROUTER = 9 \ No newline at end of file + OPENROUTER = 9 + ELEVENLABS = 10 diff --git a/Azure.py b/Azure.py index 6167729..55240f1 100644 --- a/Azure.py +++ b/Azure.py @@ -10,6 +10,8 @@ def check_azure(key: APIKey): if deployments is None: return + # deal with dall-e separately + key.dalle_deployments = [deployment['id'] for deployment in deployments if deployment['model'] == 'dall-e-3'] key.deployments = [(deployment['id'], deployment['model'], test_deployment(key, api_key, deployment['id'])) for deployment in deployments if deployment['model'].startswith('gpt')] if key.deployments is None or not key.deployments: @@ -72,6 +74,7 @@ def pretty_print_azure_keys(keys): print('-' * 90) print(f'Validated {len(keys)} Azure keys:') unfiltered = 0 + keys = sorted(keys, key=lambda x: (x.unfiltered, bool(x.dalle_deployments)), reverse=True) for key in keys: if key.unfiltered: unfiltered += 1 @@ -79,10 +82,11 @@ def pretty_print_azure_keys(keys): + f' | best deployment - {key.best_deployment}' + f' | top model - {key.model}') if key.deployments: - key_string += ' | other deployments - [' + key_string += ' | other chat deployments - [' for deployment_id, model, filter_status in key.deployments: key_string += (f"'{deployment_id}'" + (' - unfiltered' if filter_status else '') + ', ') key_string = key_string.rstrip(', ') + ']' key_string += (' | !!!UNFILTERED!!!' if key.unfiltered else '') + key_string += (f' | dall-e 3 deployments found on - {key.dalle_deployments}' if key.dalle_deployments else '') print(key_string) print(f'\n--- Total Valid Azure Keys: {len(keys)} ({unfiltered} unfiltered) ---\n') diff --git a/ElevenLabs.py b/ElevenLabs.py new file mode 100644 index 0000000..c122b82 --- /dev/null +++ b/ElevenLabs.py @@ -0,0 +1,42 @@ +import APIKey + + +async def check_elevenlabs(key: APIKey, session): + async with session.get('https://api.elevenlabs.io/v1/user/subscription', headers={'xi-api-key': key.api_key}) as response: + if response.status != 200: + return + response = await response.json() + try: + key.characters_left = int(response['character_limit']) - int(response['character_count']) + next_invoice = response['next_invoice'] + tier_pricing = [33000, 9900, 2200, 500] + key.usage = "${:.2f}".format(int(next_invoice['amount_due_cents']) / 100) if next_invoice and int(next_invoice['amount_due_cents']) not in tier_pricing else '' + key.tier = response['tier'] + key.unlimited = response['can_extend_character_limit'] and response['allowed_to_extend_character_limit'] + if response['can_use_professional_voice_cloning']: + key.pro_voice_limit = int(response['professional_voice_limit']) + except (KeyError, ValueError): + return + return True + + +def pretty_print_elevenlabs_keys(keys): + keys_by_tier = {} + for key in keys: + if key.tier not in keys_by_tier: + keys_by_tier[key.tier] = [] + keys_by_tier[key.tier].append(key) + + tier_order = ['growing_business', 'pro', 'creator', 'starter', 'free'] + + print('-' * 90) + print(f'Validated {len(keys)} ElevenLabs keys:') + for tier in tier_order: + if tier in keys_by_tier: + keys_in_tier = sorted(keys_by_tier[tier], key=lambda x: x.characters_left, reverse=True) + print(f'\n{len(keys_in_tier)} keys found in {tier} tier:') + for key in keys_in_tier: + print(f'{key.api_key} | {key.characters_left} characters remaining' + (' | !!!unlimited quota!!!' if key.unlimited else '') + + (f' | plan limit exceeded - next invoice {key.usage}' if key.usage else '') + + (f' | pro voice cloning limit of {key.pro_voice_limit}' if key.pro_voice_limit else '')) + print(f'\n--- Total Valid ElevenLabs Keys: {len(keys)} ---\n') diff --git a/README.md b/README.md index 1223b8d..28405fe 100644 --- a/README.md +++ b/README.md @@ -4,14 +4,15 @@ a fast, bulk key checker for various AI services Currently supports and validates keys for the services below, and checks for the listed attributes a key might have: - OpenAI - (Best model, key in quota, RPM (catches increase requests), tier, list of organizations if applicable, trial key status) -- Anthropic - (Pozzed and quotaless check) +- Anthropic - (Pozzed status and key tier, along with remaining character quota) - AI21 - (Trial check) - Google MakerSuite (Gemini) - AWS - (Admin status, auto-fetch the region, logging status, username, bedrock status) -- Azure - (Auto-fetch all deployments, auto-fetch best deployment/model, filter status) +- Azure - (Auto-fetch all deployments, auto-fetch best deployment/model, filter status, dall-e deployment) - Google Cloud Vertex AI - (Requires a key file since oauth tokens expire hourly. Good luck scraping for those.) - MistralAI - (Subscription status) - OpenRouter - (Estimated balance, usage in $, credit limit, RPM, has purchased any credits) +- ElevenLabs - (Key tier, remaining characters in plan, detect uncapped char quota, pro voice cloning limit, invoice details on pay as you go plans) Always open to adding more services, although I think I've covered all the ones people care about. Nonetheless, feel free to open an issue or PR if you want something else added. diff --git a/main.py b/main.py index 0795718..0cb2cec 100644 --- a/main.py +++ b/main.py @@ -8,6 +8,7 @@ from Azure import check_azure, pretty_print_azure_keys from VertexAI import check_vertexai, pretty_print_vertexai_keys from Mistral import check_mistral, pretty_print_mistral_keys from OpenRouter import check_openrouter, pretty_print_openrouter_keys +from ElevenLabs import check_elevenlabs, pretty_print_elevenlabs_keys from APIKey import APIKey, Provider from concurrent.futures import ThreadPoolExecutor, as_completed @@ -117,7 +118,7 @@ async def validate_makersuite(key: APIKey, sem): async def validate_openrouter(key: APIKey, sem): async with sem, aiohttp.ClientSession() as session: - IO.conditional_print(f"Checking OpenRouter: {key.api_key}", args.verbose) + IO.conditional_print(f"Checking OpenRouter key: {key.api_key}", args.verbose) if await check_openrouter(key, session) is None: IO.conditional_print(f"Invalid OpenRouter key: {key.api_key}", args.verbose) return @@ -125,6 +126,16 @@ async def validate_openrouter(key: APIKey, sem): api_keys.add(key) +async def validate_elevenlabs(key: APIKey, sem): + async with sem, aiohttp.ClientSession() as session: + IO.conditional_print(f"Checking ElevenLabs key: {key.api_key}", args.verbose) + if await check_elevenlabs(key, session) is None: + IO.conditional_print(f"Invalid ElevenLabs key: {key.api_key}", args.verbose) + return + IO.conditional_print(f"ElevenLabs key '{key.api_key}' is valid", args.verbose) + api_keys.add(key) + + def validate_aws(key: APIKey): IO.conditional_print(f"Checking AWS key: {key.api_key}", args.verbose) if check_aws(key) is None: @@ -156,6 +167,7 @@ oai_regex = re.compile('(sk-[A-Za-z0-9]{20}T3BlbkFJ[A-Za-z0-9]{20})') anthropic_regex = re.compile(r'sk-ant-api03-[A-Za-z0-9\-_]{93}AA') anthropic_secondary_regex = re.compile(r'sk-ant-[A-Za-z0-9\-_]{86}') ai21_and_mistral_regex = re.compile('[A-Za-z0-9]{32}') +elevenlabs_regex = re.compile(r'([a-z0-9]{32})') makersuite_regex = re.compile(r'AIzaSy[A-Za-z0-9\-_]{33}') aws_regex = re.compile(r'^(AKIA[0-9A-Z]{16}):([A-Za-z0-9+/]{40})$') azure_regex = re.compile(r'^(.+):([a-z0-9]{32})$') @@ -212,11 +224,16 @@ async def validate_keys(): key_obj = APIKey(Provider.AZURE, key) futures.append(executor.submit(validate_azure, key_obj)) else: - match = ai21_and_mistral_regex.match(key) + match = elevenlabs_regex.match(key) if not match: - continue - key_obj = APIKey(Provider.AI21, key) - tasks.append(validate_ai21_and_mistral(key_obj, concurrent_connections)) + match = ai21_and_mistral_regex.match(key) + if not match: + continue + key_obj = APIKey(Provider.AI21, key) + tasks.append(validate_ai21_and_mistral(key_obj, concurrent_connections)) + else: + key_obj = APIKey(Provider.ELEVENLABS, key) + tasks.append(validate_elevenlabs(key_obj, concurrent_connections)) results = await asyncio.gather(*tasks) for result in results: if result is not None: @@ -227,7 +244,7 @@ async def validate_keys(): futures.clear() -def get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_makersuite_keys, valid_aws_keys, valid_azure_keys, valid_vertexai_keys, valid_mistral_keys, valid_openrouter_keys): +def get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_makersuite_keys, valid_aws_keys, valid_azure_keys, valid_vertexai_keys, valid_mistral_keys, valid_openrouter_keys, valid_elevenlabs_keys): valid_oai_keys_set = set([key.api_key for key in valid_oai_keys]) valid_anthropic_keys_set = set([key.api_key for key in valid_anthropic_keys]) valid_ai21_keys_set = set([key.api_key for key in valid_ai21_keys]) @@ -237,8 +254,9 @@ def get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, vali valid_vertexai_keys_set = set([key.api_key for key in valid_vertexai_keys]) valid_mistral_keys_set = set([key.api_key for key in valid_mistral_keys]) valid_openrouter_keys_set = set([key.api_key for key in valid_openrouter_keys]) + valid_elevenlabs_set = set([key.api_key for key in valid_elevenlabs_keys]) - invalid_keys = inputted_keys - valid_oai_keys_set - valid_anthropic_keys_set - valid_ai21_keys_set - valid_makersuite_keys_set - valid_aws_keys_set - valid_azure_keys_set - valid_vertexai_keys_set - valid_mistral_keys_set - valid_openrouter_keys_set + invalid_keys = inputted_keys - valid_oai_keys_set - valid_anthropic_keys_set - valid_ai21_keys_set - valid_makersuite_keys_set - valid_aws_keys_set - valid_azure_keys_set - valid_vertexai_keys_set - valid_mistral_keys_set - valid_openrouter_keys_set - valid_elevenlabs_set invalid_keys_len = len(invalid_keys) + len(cloned_keys) if cloned_keys else len(invalid_keys) if invalid_keys_len < 1: return @@ -259,6 +277,7 @@ def output_keys(): valid_vertexai_keys = [] valid_mistral_keys = [] valid_openrouter_keys = [] + valid_elevenlabs_keys = [] for key in api_keys: if key.provider == Provider.OPENAI: @@ -279,6 +298,9 @@ def output_keys(): valid_mistral_keys.append(key) elif key.provider == Provider.OPENROUTER: valid_openrouter_keys.append(key) + elif key.provider == Provider.ELEVENLABS: + valid_elevenlabs_keys.append(key) + if should_write: output_filename = "key_snapshots.txt" sys.stdout = IO(output_filename) @@ -289,7 +311,7 @@ def output_keys(): print(f"Key snapshot from {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") print("#" * 90) print(f'\n--- Checked {len(inputted_keys)} keys | {invalid_keys} were invalid ---') - get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_makersuite_keys, valid_aws_keys, valid_azure_keys, valid_vertexai_keys, valid_mistral_keys, valid_openrouter_keys) + get_invalid_keys(valid_oai_keys, valid_anthropic_keys, valid_ai21_keys, valid_makersuite_keys, valid_aws_keys, valid_azure_keys, valid_vertexai_keys, valid_mistral_keys, valid_openrouter_keys, valid_elevenlabs_keys) print() if valid_oai_keys: pretty_print_oai_keys(valid_oai_keys, cloned_keys) @@ -309,6 +331,8 @@ def output_keys(): pretty_print_mistral_keys(valid_mistral_keys) if valid_openrouter_keys: pretty_print_openrouter_keys(valid_openrouter_keys) + if valid_elevenlabs_keys: + pretty_print_elevenlabs_keys(valid_elevenlabs_keys) else: # ai21, openrouter and vertex keys aren't supported in proxies so no point outputting them, filtered azure keys should be excluded. print("OPENAI_KEY=" + ','.join(key.api_key for key in valid_oai_keys))