diff --git a/api/config/config.yml b/api/config/config.yml new file mode 100644 index 0000000..593392c --- /dev/null +++ b/api/config/config.yml @@ -0,0 +1,59 @@ +max-credits: 100001 +max-credits-owner: 694201337 +start-credits: 1000 + +costs: + other: 10 + + chat-models: + gpt-3: 10 + gpt-4: 30 + gpt-4-32k: 100 + +## Roles Explanation + +# Bonuses: They are a multiplier for costs +# They work like: final_cost = cost * bonus +# Rate limits: Limit the requests of the user +# The rate limit is by how many seconds until a new request can be done. + +## TODO: Setup proper rate limit settings for each role +## Current settings are: +## **NOT MEANT FOR PRODUCTION. DO NOT USE WITH THESE SETTINGS.** + +roles: + owner: + bonus: 0.1 + rate_limit: + other: 60 + gpt-3: 60 + gpt-4: 35 + gpt-4-32k: 5 + admin: + bonus: 0.3 + rate_limit: + other: 60 + gpt-3: 60 + gpt-4: 30 + gpt-4-32k: 4 + helper: + bonus: 0.4 + rate_limit: + other: 60 + gpt-3: 60 + gpt-4: 25 + gpt-4-32k: 3 + booster: + bonus: 0.5 + rate_limit: + other: 60 + gpt-3: 60 + gpt-4: 20 + gpt-4-32k: 2 + default: + bonus: 0 + rate_limit: + other: 60 + gpt-3: 60 + gpt-4: 15 + gpt-4-32k: 1 \ No newline at end of file diff --git a/api/config/credits.yml b/api/config/credits.yml deleted file mode 100644 index 29eeaa9..0000000 --- a/api/config/credits.yml +++ /dev/null @@ -1,19 +0,0 @@ -max-credits: 100001 -max-credits-owner: 694201337 -start-credits: 1000 - -costs: - other: 10 - - chat-models: - gpt-3: 10 - gpt-4: 30 - gpt-4-32k: 100 - -# bonuses are multiplier for costs: -# final_cost = cost * bonus -bonuses: - owner: 0.1 - admin: 0.3 - helper: 0.4 - booster: 0.5 diff --git a/api/db/stats.py b/api/db/stats.py index b2edeee..4fe7c56 100644 --- a/api/db/stats.py +++ b/api/db/stats.py @@ -26,7 +26,7 @@ class StatsManager: self.conn = AsyncIOMotorClient(os.getenv('MONGO_URI')) async def _get_collection(self, collection_name: str): - return self.conn[os.getenv('MONGO_NAME', 'nova-test')][collection_name] + return self.conn['nova-core'][collection_name] async def add_date(self): date = datetime.datetime.now(pytz.timezone('GMT')).strftime('%Y.%m.%d') @@ -62,5 +62,6 @@ class StatsManager: return await db.find_one({obj_filter}) if __name__ == '__main__': - asyncio.run(Stats.add_date()) - asyncio.run(Stats.add_path('/__demo/test')) + stats = StatsManager() + asyncio.run(stats.add_date()) + asyncio.run(stats.add_path('/__demo/test')) diff --git a/api/db/users.py b/api/db/users.py index 056c399..63073d5 100644 --- a/api/db/users.py +++ b/api/db/users.py @@ -9,7 +9,7 @@ from motor.motor_asyncio import AsyncIOMotorClient load_dotenv() -with open('config/credits.yml', encoding='utf8') as f: +with open('config/config.yml', encoding='utf8') as f: credits_config = yaml.safe_load(f) ## MONGODB Setup diff --git a/api/streaming.py b/api/streaming.py index 5ed64cf..4ff7ecc 100644 --- a/api/streaming.py +++ b/api/streaming.py @@ -26,12 +26,12 @@ import yaml load_dotenv() ## Loads config which contains rate limits -with open('config/credits.yml', encoding='utf8') as f: +with open('config/config.yml', encoding='utf8') as f: config = yaml.safe_load(f) ## Where all rate limit requested data will be stored. # Rate limit data is **not persistent** (It will be deleted on server stop/restart). -# user_last_request_time = {} +user_last_request_time = {} DEMO_PAYLOAD = { 'model': 'gpt-3.5-turbo', @@ -93,18 +93,18 @@ async def stream( ## Rate limits user. # If rate limit is exceeded, error code 429. Otherwise, lets the user pass but notes down # last request time for future requests. - # if user: - # role = user.get('role', 'default') - # rate_limit = config['roles'][role]['rate_limit'].get(payload['model'], 10) + if user: + role = user.get('role', 'default') + rate_limit = config['roles'].get(role, 1)['rate_limit'].get(payload['model'], 1) - # last_request_time = user_last_request_time.get(user['api_key']) - # time_since_last_request = datetime.datetime.now() - last_request_time + last_request_time = user_last_request_time.get(user['api_key']) + time_since_last_request = datetime.now() - last_request_time - # if time_since_last_request < datetime.timedelta(seconds=rate_limit): - # yield await errors.yield_error(429, 'Rate limit exceeded', "You are making requests too quickly. Please wait and try again later. Ask a administrator if you think this shouldn't happen.") - # return - # else: - # user_last_request_time[user['_id']] = datetime.datetime.now() + if time_since_last_request < datetime.timedelta(seconds=rate_limit): + yield await errors.yield_error(429, "Rate limit exceeded', 'You are making requests too quickly. Please wait and try again later. Ask a administrator if you think this shouldn't happen. ") + return + else: + user_last_request_time[user['_id']] = datetime.now() ## Setup managers db = UserManager() diff --git a/api/transfer.py b/api/transfer.py index 77e586f..98c3093 100644 --- a/api/transfer.py +++ b/api/transfer.py @@ -16,8 +16,8 @@ load_dotenv() models_list = json.load(open('models.json')) -with open('config/credits.yml', encoding='utf8') as f: - credits_config = yaml.safe_load(f) +with open('config/config.yml', encoding='utf8') as f: + config = yaml.safe_load(f) async def handle(incoming_request): """ @@ -62,7 +62,7 @@ async def handle(incoming_request): if path_contains_models: return fastapi.responses.JSONResponse(content=models_list) - costs = credits_config['costs'] + costs = config['costs'] cost = costs['other'] if 'chat/completions' in path: @@ -77,7 +77,8 @@ async def handle(incoming_request): if policy_violation: return await errors.error(400, f'The request contains content which violates this model\'s policies for "{policy_violation}".', 'We currently don\'t support any NSFW models.') - role_cost_multiplier = credits_config['bonuses'].get(user['role'], 1) + role = user.get('role', 'default') + role_cost_multiplier = config['roles'].get(role, 1)['bonus'] cost = round(cost * role_cost_multiplier) if user['credits'] < cost: diff --git a/rewards/autocredits.py b/rewards/autocredits.py index f7ea815..8aee8ff 100644 --- a/rewards/autocredits.py +++ b/rewards/autocredits.py @@ -1,15 +1,12 @@ -import os +import sys +# Weird hack because PYTHON IS GOOD LANGUAGE :)))) +sys.path.append('../') +from api.db.users import UserManager -from dotenv import load_dotenv - -load_dotenv() - -async def get_all_users(client): - users = client[os.getenv('MONGO_NAME', 'nova-test')]['users'] - return users async def update_credits(pymongo_client, settings=None): - users = await get_all_users(pymongo_client) + manager = UserManager() + users = await manager.get_all_users(pymongo_client) if not settings: users.update_many({}, {'$inc': {'credits': 2500}}) @@ -17,8 +14,4 @@ async def update_credits(pymongo_client, settings=None): else: for key, value in settings.items(): users.update_many( - {'level': key}, - {'$inc': - {'credits': int(value)} - } - ) + {'level': key}, {'$inc': {'credits': int(value)}}) diff --git a/tests/__main__.py b/tests/__main__.py index 500ae92..402b966 100644 --- a/tests/__main__.py +++ b/tests/__main__.py @@ -10,16 +10,7 @@ from dotenv import load_dotenv load_dotenv() MODEL = 'gpt-3.5-turbo' -# MESSAGES = [ -# { -# 'role': 'system', -# 'content': 'Always answer with "3", no matter what the user asks for. No exceptions. Just answer with the number "3". Nothing else. Just "3". No punctuation.' -# }, -# { -# 'role': 'user', -# 'content': '1+1=', -# }, -# ] + MESSAGES = [ { 'role': 'user',