Compare commits

..

3 commits

Author SHA1 Message Date
monosans 15b4aed848
Merge 4236017ef8 into 21331874db 2023-10-06 14:42:48 +00:00
monosans 4236017ef8
Avoid using f.readlines() 2023-10-06 17:42:42 +03:00
monosans 1a858cd47d
Refactor file operations 2023-10-06 11:19:29 +03:00
10 changed files with 57 additions and 149 deletions

View file

@ -6,10 +6,9 @@ costs:
other: 5 other: 5
chat-models: chat-models:
gpt-4-32k-azure: 100 gpt-4-32k: 100
gpt-4: 50 gpt-4: 30
gpt-4-azure: 10 gpt-3: 3
gpt-3: 5
## Roles Explanation ## Roles Explanation

View file

@ -1,19 +1,14 @@
import os import os
import time import time
import random
import asyncio import asyncio
import aiofiles import aiofiles
import aiofiles.os import aiofiles.os
from aiocache import cached
from dotenv import load_dotenv from dotenv import load_dotenv
from cachetools import TTLCache
from motor.motor_asyncio import AsyncIOMotorClient from motor.motor_asyncio import AsyncIOMotorClient
load_dotenv() load_dotenv()
cache = TTLCache(maxsize=100, ttl=10)
class KeyManager: class KeyManager:
def __init__(self): def __init__(self):
self.conn = AsyncIOMotorClient(os.environ['MONGO_URI']) self.conn = AsyncIOMotorClient(os.environ['MONGO_URI'])
@ -31,34 +26,27 @@ class KeyManager:
'source': source, 'source': source,
}) })
async def get_possible_keys(self, provider: str): async def get_key(self, provider: str):
db = await self._get_collection('providerkeys') db = await self._get_collection('providerkeys')
keys = await db.find({ key = await db.find_one({
'provider': provider, 'provider': provider,
'inactive_reason': None, 'inactive_reason': None,
'$or': [ '$or': [
{'rate_limited_until': None}, {'rate_limited_since': None},
{'rate_limited_until': {'$lte': time.time()}} {'rate_limited_since': {'$lte': time.time() - 86400}}
] ]
}).to_list(length=None) })
return keys if key is None:
async def get_key(self, provider: str):
keys = await self.get_possible_keys(provider)
if not keys:
return '--NO_KEY--' return '--NO_KEY--'
key = random.choice(keys) return key['key']
api_key = key['key']
return api_key
async def rate_limit_key(self, provider: str, key: str, duration: int): async def rate_limit_key(self, provider: str, key: str):
db = await self._get_collection('providerkeys') db = await self._get_collection('providerkeys')
await db.update_one({'provider': provider, 'key': key}, { await db.update_one({'provider': provider, 'key': key}, {
'$set': { '$set': {
'rate_limited_until': time.time() + duration 'rate_limited_since': time.time()
} }
}) })
@ -84,6 +72,8 @@ class KeyManager:
await db.insert_one({ await db.insert_one({
'provider': filename.split('.')[0], 'provider': filename.split('.')[0],
'key': line.strip(), 'key': line.strip(),
'rate_limited_since': None,
'inactive_reason': None,
'source': 'import' 'source': 'import'
}) })
num += 1 num += 1
@ -98,9 +88,5 @@ class KeyManager:
manager = KeyManager() manager = KeyManager()
async def main():
keys = await manager.get_possible_keys('closed')
print(len(keys))
if __name__ == '__main__': if __name__ == '__main__':
asyncio.run(main()) asyncio.run(manager.import_all())

View file

@ -70,8 +70,8 @@ async def handle(incoming_request: fastapi.Request):
return await errors.error(403, f'Your NovaAI account has been banned. Reason: \'{ban_reason}\'.', 'Contact the staff for an appeal.') return await errors.error(403, f'Your NovaAI account has been banned. Reason: \'{ban_reason}\'.', 'Contact the staff for an appeal.')
# Checking for enterprise status # Checking for enterprise status
enterprise_keys = os.environ.get('ENTERPRISE_KEYS') enterprise_keys = os.environ.get('NO_RATELIMIT_KEYS')
if path.startswith('/enterprise/v1') and user.get('api_key') not in enterprise_keys.split(): if '/enterprise' in path and user.get('api_key') not in enterprise_keys:
return await errors.error(403, 'Enterprise API is not available.', 'Contact the staff for an upgrade.') return await errors.error(403, 'Enterprise API is not available.', 'Contact the staff for an upgrade.')
if 'account/credits' in path: if 'account/credits' in path:

View file

@ -1,11 +1,9 @@
from . import \ from . import \
azure, \
closed, \ closed, \
closed4 closed4
# closed432 # closed432
MODULES = [ MODULES = [
azure,
closed, closed,
closed4, closed4,
# closed432, # closed432,

View file

@ -1,9 +1,5 @@
import os import os
import sys import sys
import aiohttp
import asyncio
import importlib
import aiofiles.os
from rich import print from rich import print
@ -14,43 +10,41 @@ def remove_duplicate_keys(file):
with open(file, 'w', encoding='utf8') as f: with open(file, 'w', encoding='utf8') as f:
f.writelines(unique_lines) f.writelines(unique_lines)
async def main(): try:
try: provider_name = sys.argv[1]
provider_name = sys.argv[1]
except IndexError: if provider_name == '--clear':
print('List of available providers:') for file in os.listdir('secret'):
if file.endswith('.txt'):
remove_duplicate_keys(os.path.join('secret', file))
for file_name in await aiofiles.os.listdir(os.path.dirname(__file__)): exit()
if file_name.endswith('.py') and not file_name.startswith('_'):
print(file_name.split('.')[0])
sys.exit(0) except IndexError:
print('List of available providers:')
try: for file_name in os.listdir(os.path.dirname(__file__)):
provider = importlib.import_module(f'.{provider_name}', 'providers') if file_name.endswith('.py') and not file_name.startswith('_'):
except ModuleNotFoundError as exc: print(file_name.split('.')[0])
print(exc)
sys.exit(1)
if len(sys.argv) > 2: sys.exit(0)
model = sys.argv[2] # choose a specific model
else:
model = provider.MODELS[-1] # choose best model
print(f'{provider_name} @ {model}') try:
req = await provider.chat_completion(model=model, messages=[{'role': 'user', 'content': '1+1='}]) provider = __import__(provider_name)
print(req) except ModuleNotFoundError as exc:
print(f'Provider "{provider_name}" not found.')
print('Available providers:')
for file_name in os.listdir(os.path.dirname(__file__)):
if file_name.endswith('.py') and not file_name.startswith('_'):
print(file_name.split('.')[0])
sys.exit(1)
# launch aiohttp if len(sys.argv) > 2:
async with aiohttp.ClientSession() as session: model = sys.argv[2]
async with session.request( else:
method=req['method'], model = provider.MODELS[-1]
url=req['url'],
headers=req['headers'],
json=req['payload'],
) as response:
res_json = await response.json()
print(response.status, res_json)
asyncio.run(main())
print(f'{provider_name} @ {model}')
comp = provider.chat_completion(model=model)
print(comp)

View file

@ -1,32 +0,0 @@
from .helpers import utils
AUTH = True
ORGANIC = False
CONTEXT = True
STREAMING = True
MODERATIONS = False
ENDPOINT = 'https://nova-00001.openai.azure.com'
MODELS = [
'gpt-3.5-turbo',
'gpt-3.5-turbo-16k',
'gpt-4',
'gpt-4-32k'
]
MODELS = [f'{model}-azure' for model in MODELS]
AZURE_API = '2023-07-01-preview'
async def chat_completion(**payload):
key = await utils.random_secret_for('azure-nva1')
deployment = payload['model'].replace('.', '').replace('-azure', '')
return {
'method': 'POST',
'url': f'{ENDPOINT}/openai/deployments/{deployment}/chat/completions?api-version={AZURE_API}',
'payload': payload,
'headers': {
'api-key': key
},
'provider_auth': f'azure-nva1>{key}'
}

View file

@ -1,7 +1,4 @@
try: from db import providerkeys
from db import providerkeys
except ModuleNotFoundError:
from ...db import providerkeys
GPT_3 = [ GPT_3 = [
'gpt-3.5-turbo', 'gpt-3.5-turbo',

View file

@ -1,21 +0,0 @@
from .helpers import utils
AUTH = True
ORGANIC = False
CONTEXT = True
STREAMING = True
MODELS = ['llama-2-7b-chat']
async def chat_completion(**kwargs):
payload = kwargs
key = await utils.random_secret_for('mandrill')
return {
'method': 'POST',
'url': f'https://api.mandrillai.tech/v1/chat/completions',
'payload': payload,
'headers': {
'Authorization': f'Bearer {key}'
},
'provider_auth': f'mandrill>{key}'
}

View file

@ -49,8 +49,7 @@ async def respond(
'Content-Type': 'application/json' 'Content-Type': 'application/json'
} }
for i in range(20): for _ in range(20):
print(i)
# Load balancing: randomly selecting a suitable provider # Load balancing: randomly selecting a suitable provider
try: try:
if is_chat: if is_chat:
@ -63,7 +62,6 @@ async def respond(
'headers': headers, 'headers': headers,
'cookies': incoming_request.cookies 'cookies': incoming_request.cookies
}) })
except ValueError: except ValueError:
yield await errors.yield_error(500, f'Sorry, the API has no active API keys for {model}.', 'Please use a different model.') yield await errors.yield_error(500, f'Sorry, the API has no active API keys for {model}.', 'Please use a different model.')
return return
@ -75,7 +73,6 @@ async def respond(
provider_key = provider_auth.split('>')[1] provider_key = provider_auth.split('>')[1]
if provider_key == '--NO_KEY--': if provider_key == '--NO_KEY--':
print(f'No key for {provider_name}')
yield await errors.yield_error(500, yield await errors.yield_error(500,
'Sorry, our API seems to have issues connecting to our provider(s).', 'Sorry, our API seems to have issues connecting to our provider(s).',
'This most likely isn\'t your fault. Please try again later.' 'This most likely isn\'t your fault. Please try again later.'
@ -104,26 +101,16 @@ async def respond(
) as response: ) as response:
is_stream = response.content_type == 'text/event-stream' is_stream = response.content_type == 'text/event-stream'
if response.status == 429:
print('[!] rate limit')
# await keymanager.rate_limit_key(provider_name, provider_key)
continue
if response.content_type == 'application/json': if response.content_type == 'application/json':
client_json_response = await response.json() client_json_response = await response.json()
try: if 'method_not_supported' in str(client_json_response):
error_code = client_json_response['error']['code'] await errors.error(500, 'Sorry, this endpoint does not support this method.', data['error']['message'])
except KeyError:
error_code = ''
if error_code == 'method_not_supported':
yield await errors.yield_error(400, 'Sorry, this endpoint does not support this method.', 'Please use a different method.')
if error_code == 'insufficient_quota':
print('[!] insufficient quota')
await keymanager.rate_limit_key(provider_name, provider_key, 86400)
continue
if error_code == 'billing_not_active':
print('[!] billing not active')
await keymanager.deactivate_key(provider_name, provider_key, 'billing_not_active')
continue
critical_error = False critical_error = False
for error in CRITICAL_API_ERRORS: for error in CRITICAL_API_ERRORS:
@ -139,6 +126,7 @@ async def respond(
server_json_response = client_json_response server_json_response = client_json_response
else: else:
print('[!] non-ok response', client_json_response)
continue continue
if is_stream: if is_stream:

View file

@ -25,7 +25,6 @@ MESSAGES = [
] ]
api_endpoint = os.getenv('CHECKS_ENDPOINT', 'http://localhost:2332/v1') api_endpoint = os.getenv('CHECKS_ENDPOINT', 'http://localhost:2332/v1')
# api_endpoint = 'http://localhost:2333/v1'
async def _response_base_check(response: httpx.Response) -> None: async def _response_base_check(response: httpx.Response) -> None:
try: try: