mirror of
https://github.com/NovaOSS/nova-api.git
synced 2024-11-25 20:53:58 +01:00
Compare commits
3 commits
abb18ad1bf
...
f9edbf1bc0
Author | SHA1 | Date | |
---|---|---|---|
f9edbf1bc0 | |||
f6cd1f7aa2 | |||
8c05fd9d87 |
|
@ -1,59 +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
|
|
||||||
|
|
||||||
## 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
|
|
19
api/config/credits.yml
Normal file
19
api/config/credits.yml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
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
|
|
@ -21,7 +21,7 @@ UA_SIMPLIFY = {
|
||||||
conn = AsyncIOMotorClient(os.getenv('MONGO_URI'))
|
conn = AsyncIOMotorClient(os.getenv('MONGO_URI'))
|
||||||
|
|
||||||
async def _get_collection(collection_name: str):
|
async def _get_collection(collection_name: str):
|
||||||
return conn['nova-core'][collection_name]
|
return conn[os.getenv('MONGO_NAME', 'nova-test')][collection_name]
|
||||||
|
|
||||||
async def replacer(text: str, dict_: dict) -> str:
|
async def replacer(text: str, dict_: dict) -> str:
|
||||||
# This seems to exist for a very specific and dumb purpose :D
|
# This seems to exist for a very specific and dumb purpose :D
|
||||||
|
|
|
@ -26,7 +26,7 @@ class StatsManager:
|
||||||
self.conn = AsyncIOMotorClient(os.getenv('MONGO_URI'))
|
self.conn = AsyncIOMotorClient(os.getenv('MONGO_URI'))
|
||||||
|
|
||||||
async def _get_collection(self, collection_name: str):
|
async def _get_collection(self, collection_name: str):
|
||||||
return self.conn['nova-core'][collection_name]
|
return self.conn[os.getenv('MONGO_NAME', 'nova-test')][collection_name]
|
||||||
|
|
||||||
async def add_date(self):
|
async def add_date(self):
|
||||||
date = datetime.datetime.now(pytz.timezone('GMT')).strftime('%Y.%m.%d')
|
date = datetime.datetime.now(pytz.timezone('GMT')).strftime('%Y.%m.%d')
|
||||||
|
|
|
@ -9,7 +9,7 @@ from motor.motor_asyncio import AsyncIOMotorClient
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
with open('config/config.yml', encoding='utf8') as f:
|
with open('config/credits.yml', encoding='utf8') as f:
|
||||||
credits_config = yaml.safe_load(f)
|
credits_config = yaml.safe_load(f)
|
||||||
|
|
||||||
## MONGODB Setup
|
## MONGODB Setup
|
||||||
|
@ -33,10 +33,10 @@ class UserManager:
|
||||||
self.conn = AsyncIOMotorClient(os.getenv('MONGO_URI'))
|
self.conn = AsyncIOMotorClient(os.getenv('MONGO_URI'))
|
||||||
|
|
||||||
async def _get_collection(self, collection_name: str):
|
async def _get_collection(self, collection_name: str):
|
||||||
return self.conn['nova-core'][collection_name]
|
return self.conn[os.getenv('MONGO_NAME', 'nova-test')][collection_name]
|
||||||
|
|
||||||
async def get_all_users(self):
|
async def get_all_users(self):
|
||||||
return self.conn['nova-core']['users']
|
return self.conn[os.getenv('MONGO_NAME', 'nova-test')]['users']
|
||||||
|
|
||||||
async def create(self, discord_id: str = '') -> dict:
|
async def create(self, discord_id: str = '') -> dict:
|
||||||
chars = string.ascii_letters + string.digits
|
chars = string.ascii_letters + string.digits
|
||||||
|
|
|
@ -26,12 +26,12 @@ import yaml
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
## Loads config which contains rate limits
|
## Loads config which contains rate limits
|
||||||
with open('config/config.yml', encoding='utf8') as f:
|
with open('config/credits.yml', encoding='utf8') as f:
|
||||||
config = yaml.safe_load(f)
|
config = yaml.safe_load(f)
|
||||||
|
|
||||||
## Where all rate limit requested data will be stored.
|
## Where all rate limit requested data will be stored.
|
||||||
# Rate limit data is **not persistent** (It will be deleted on server stop/restart).
|
# Rate limit data is **not persistent** (It will be deleted on server stop/restart).
|
||||||
user_last_request_time = {}
|
# user_last_request_time = {}
|
||||||
|
|
||||||
DEMO_PAYLOAD = {
|
DEMO_PAYLOAD = {
|
||||||
'model': 'gpt-3.5-turbo',
|
'model': 'gpt-3.5-turbo',
|
||||||
|
@ -93,18 +93,18 @@ async def stream(
|
||||||
## Rate limits user.
|
## Rate limits user.
|
||||||
# If rate limit is exceeded, error code 429. Otherwise, lets the user pass but notes down
|
# If rate limit is exceeded, error code 429. Otherwise, lets the user pass but notes down
|
||||||
# last request time for future requests.
|
# last request time for future requests.
|
||||||
if user:
|
# if user:
|
||||||
role = user.get('role', 'default')
|
# role = user.get('role', 'default')
|
||||||
rate_limit = config['roles'][role]['rate_limit'].get(payload['model'], 10)
|
# rate_limit = config['roles'][role]['rate_limit'].get(payload['model'], 10)
|
||||||
|
|
||||||
last_request_time = user_last_request_time.get(user['api_key'])
|
# last_request_time = user_last_request_time.get(user['api_key'])
|
||||||
time_since_last_request = datetime.now() - last_request_time
|
# time_since_last_request = datetime.datetime.now() - last_request_time
|
||||||
|
|
||||||
if time_since_last_request < datetime.timedelta(seconds=rate_limit):
|
# 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. ")
|
# 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
|
# return
|
||||||
else:
|
# else:
|
||||||
user_last_request_time[user['_id']] = datetime.now()
|
# user_last_request_time[user['_id']] = datetime.datetime.now()
|
||||||
|
|
||||||
## Setup managers
|
## Setup managers
|
||||||
db = UserManager()
|
db = UserManager()
|
||||||
|
@ -169,7 +169,10 @@ async def stream(
|
||||||
headers=target_request.get('headers', {}),
|
headers=target_request.get('headers', {}),
|
||||||
cookies=target_request.get('cookies'),
|
cookies=target_request.get('cookies'),
|
||||||
ssl=False,
|
ssl=False,
|
||||||
timeout=aiohttp.ClientTimeout(total=float(os.getenv('TRANSFER_TIMEOUT', '120'))),
|
timeout=aiohttp.ClientTimeout(
|
||||||
|
connect=3.0,
|
||||||
|
total=float(os.getenv('TRANSFER_TIMEOUT', '120'))
|
||||||
|
),
|
||||||
) as response:
|
) as response:
|
||||||
if response.content_type == 'application/json':
|
if response.content_type == 'application/json':
|
||||||
data = await response.json()
|
data = await response.json()
|
||||||
|
|
|
@ -16,8 +16,8 @@ load_dotenv()
|
||||||
|
|
||||||
models_list = json.load(open('models.json'))
|
models_list = json.load(open('models.json'))
|
||||||
|
|
||||||
with open('config/config.yml', encoding='utf8') as f:
|
with open('config/credits.yml', encoding='utf8') as f:
|
||||||
config = yaml.safe_load(f)
|
credits_config = yaml.safe_load(f)
|
||||||
|
|
||||||
async def handle(incoming_request):
|
async def handle(incoming_request):
|
||||||
"""
|
"""
|
||||||
|
@ -62,7 +62,7 @@ async def handle(incoming_request):
|
||||||
if path_contains_models:
|
if path_contains_models:
|
||||||
return fastapi.responses.JSONResponse(content=models_list)
|
return fastapi.responses.JSONResponse(content=models_list)
|
||||||
|
|
||||||
costs = config['costs']
|
costs = credits_config['costs']
|
||||||
cost = costs['other']
|
cost = costs['other']
|
||||||
|
|
||||||
if 'chat/completions' in path:
|
if 'chat/completions' in path:
|
||||||
|
@ -77,7 +77,7 @@ async def handle(incoming_request):
|
||||||
if policy_violation:
|
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.')
|
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 = config['roles'][user['role']]['bonus']
|
role_cost_multiplier = credits_config['bonuses'].get(user['role'], 1)
|
||||||
cost = round(cost * role_cost_multiplier)
|
cost = round(cost * role_cost_multiplier)
|
||||||
|
|
||||||
if user['credits'] < cost:
|
if user['credits'] < cost:
|
||||||
|
|
|
@ -1,9 +1,15 @@
|
||||||
from users import UserManager
|
import os
|
||||||
|
|
||||||
|
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):
|
async def update_credits(pymongo_client, settings=None):
|
||||||
manager = UserManager()
|
users = await get_all_users(pymongo_client)
|
||||||
users = await manager.get_all_users(pymongo_client)
|
|
||||||
|
|
||||||
if not settings:
|
if not settings:
|
||||||
users.update_many({}, {'$inc': {'credits': 2500}})
|
users.update_many({}, {'$inc': {'credits': 2500}})
|
||||||
|
@ -11,4 +17,8 @@ async def update_credits(pymongo_client, settings=None):
|
||||||
else:
|
else:
|
||||||
for key, value in settings.items():
|
for key, value in settings.items():
|
||||||
users.update_many(
|
users.update_many(
|
||||||
{'level': key}, {'$inc': {'credits': int(value)}})
|
{'level': key},
|
||||||
|
{'$inc':
|
||||||
|
{'credits': int(value)}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
12
screen.sh
12
screen.sh
|
@ -1 +1,13 @@
|
||||||
|
# Script to start the production server
|
||||||
|
|
||||||
|
# Copy files to production
|
||||||
|
cp -r * /home/nova-prod
|
||||||
|
|
||||||
|
# Copy env file to production
|
||||||
|
cp env/.prod.env /home/nova-prod/.env
|
||||||
|
|
||||||
|
# Change directory
|
||||||
|
cd /home/nova-prod
|
||||||
|
|
||||||
|
# Start screen
|
||||||
screen -S nova-api python run prod
|
screen -S nova-api python run prod
|
||||||
|
|
|
@ -69,7 +69,10 @@ def test_library():
|
||||||
return completion['choices'][0]['message']['content']
|
return completion['choices'][0]['message']['content']
|
||||||
|
|
||||||
def test_library_moderation():
|
def test_library_moderation():
|
||||||
|
try:
|
||||||
return closedai.Moderation.create('I wanna kill myself, I wanna kill myself; It\'s all I hear right now, it\'s all I hear right now')
|
return closedai.Moderation.create('I wanna kill myself, I wanna kill myself; It\'s all I hear right now, it\'s all I hear right now')
|
||||||
|
except closedai.errors.InvalidRequestError as exc:
|
||||||
|
return True
|
||||||
|
|
||||||
def test_models():
|
def test_models():
|
||||||
response = httpx.get(
|
response = httpx.get(
|
||||||
|
|
Loading…
Reference in a new issue