Compare commits

..

No commits in common. "f0fee481db9794cd4ca5f4ece5000c79424a14e0" and "e589b87fb48ce9a08fb08865dd4d152ae8ee8b9b" have entirely different histories.

8 changed files with 37 additions and 1401 deletions

View file

@ -15,7 +15,7 @@ with open('config/credits.yml', encoding='utf8') as f:
async def _get_mongo(collection_name: str): async def _get_mongo(collection_name: str):
return AsyncIOMotorClient(os.getenv('MONGO_URI'))['nova-core'][collection_name] return AsyncIOMotorClient(os.getenv('MONGO_URI'))['nova-core'][collection_name]
async def create(discord_id: str='') -> dict: async def create(discord_id: int=0) -> dict:
"""Adds a new user to the MongoDB collection.""" """Adds a new user to the MongoDB collection."""
chars = string.ascii_letters + string.digits chars = string.ascii_letters + string.digits
@ -36,7 +36,7 @@ async def create(discord_id: str='') -> dict:
'ban_reason': '', 'ban_reason': '',
}, },
'auth': { 'auth': {
'discord': str(discord_id), 'discord': discord_id,
'github': None 'github': None
} }
} }
@ -52,7 +52,7 @@ async def by_id(user_id: str):
async def by_discord_id(discord_id: str): async def by_discord_id(discord_id: str):
db = await _get_mongo('users') db = await _get_mongo('users')
return await db.find_one({'auth.discord': str(int(discord_id))}) return await db.find_one({'auth.discord': discord_id})
async def by_api_key(key: str): async def by_api_key(key: str):
db = await _get_mongo('users') db = await _get_mongo('users')

File diff suppressed because it is too large Load diff

View file

@ -47,8 +47,7 @@ async def is_policy_violated(inp) -> bool:
return False return False
except Exception as exc: except Exception as exc:
if '401' in str(exc): # await provider_auth.invalidate_key(req.get('provider_auth'))
await provider_auth.invalidate_key(req.get('provider_auth'))
print('[!] moderation error:', type(exc), exc) print('[!] moderation error:', type(exc), exc)
continue continue

View file

@ -10,7 +10,6 @@ from dotenv import load_dotenv
from python_socks._errors import ProxyError from python_socks._errors import ProxyError
import proxies import proxies
import provider_auth
import load_balancing import load_balancing
from db import logs, users, stats from db import logs, users, stats
@ -37,6 +36,8 @@ async def stream(
input_tokens: int=0, input_tokens: int=0,
incoming_request: starlette.requests.Request=None, incoming_request: starlette.requests.Request=None,
): ):
payload = payload or DEMO_PAYLOAD
is_chat = False is_chat = False
is_stream = payload.get('stream', False) is_stream = payload.get('stream', False)
@ -44,6 +45,7 @@ async def stream(
is_chat = True is_chat = True
model = payload['model'] model = payload['model']
if is_chat and is_stream: if is_chat and is_stream:
chat_id = await chat.create_chat_id() chat_id = await chat.create_chat_id()
@ -86,7 +88,7 @@ async def stream(
webhook = dhooks.Webhook(os.getenv('DISCORD_WEBHOOK__API_ISSUE')) webhook = dhooks.Webhook(os.getenv('DISCORD_WEBHOOK__API_ISSUE'))
webhook.send(content=f'API Issue: **`{exc}`**\nhttps://i.imgflip.com/7uv122.jpg') webhook.send(content=f'API Issue: **`{exc}`**\nhttps://i.imgflip.com/7uv122.jpg')
error = await errors.yield_error( error = errors.yield_error(
500, 500,
'Sorry, the API has no working keys anymore.', 'Sorry, the API has no working keys anymore.',
'The admins have been messaged automatically.' 'The admins have been messaged automatically.'
@ -95,10 +97,7 @@ async def stream(
return return
for k, v in target_request.get('headers', {}).items(): for k, v in target_request.get('headers', {}).items():
target_request['headers'][k] = v headers[k] = v
if target_request['method'] == 'GET' and not payload:
target_request['payload'] = None
async with aiohttp.ClientSession(connector=proxies.default_proxy.connector) as session: async with aiohttp.ClientSession(connector=proxies.default_proxy.connector) as session:
try: try:
@ -109,30 +108,24 @@ async def stream(
data=target_request.get('data'), data=target_request.get('data'),
json=target_request.get('payload'), json=target_request.get('payload'),
headers=target_request.get('headers', {}), headers=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(total=float(os.getenv('TRANSFER_TIMEOUT', '120'))),
) as response: ) as response:
if response.content_type == 'application/json':
data = await response.json()
if data.get('code') == 'invalid_api_key': if not is_stream:
await provider_auth.invalidate_key(target_request.get('provider_auth')) json_response = await response.json()
continue
if response.ok:
json_response = data
if is_stream:
try: try:
response.raise_for_status() response.raise_for_status()
except Exception as exc: except Exception as exc:
if 'Too Many Requests' in str(exc): if 'Too Many Requests' in str(exc):
continue continue
if is_stream:
try: try:
async for chunk in response.content.iter_any(): async for chunk in response.content.iter_any():
send = False send = False
@ -166,7 +159,7 @@ async def stream(
except Exception as exc: except Exception as exc:
if 'Connection closed' in str(exc): if 'Connection closed' in str(exc):
error = await errors.yield_error( error = errors.yield_error(
500, 500,
'Sorry, there was an issue with the connection.', 'Sorry, there was an issue with the connection.',
'Please first check if the issue on your end. If this error repeats, please don\'t heistate to contact the staff!.' 'Please first check if the issue on your end. If this error repeats, please don\'t heistate to contact the staff!.'
@ -187,9 +180,10 @@ async def stream(
content=chat.CompletionStop content=chat.CompletionStop
) )
yield chunk yield chunk
yield 'data: [DONE]\n\n' yield 'data: [DONE]\n\n'
if not is_stream and json_response: if not is_stream:
yield json.dumps(json_response) yield json.dumps(json_response)
# DONE ========================================================= # DONE =========================================================

View file

@ -14,8 +14,6 @@ from helpers import tokens, errors
load_dotenv() load_dotenv()
models_list = json.load(open('models.json'))
with open('config/credits.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)
@ -67,9 +65,6 @@ async def handle(incoming_request):
error = await errors.error(418, 'Your NovaAI account is not active (paused).', 'Simply re-activate your account using a Discord command or the web panel.') error = await errors.error(418, 'Your NovaAI account is not active (paused).', 'Simply re-activate your account using a Discord command or the web panel.')
return error return error
if '/models' in path:
return fastapi.responses.JSONResponse(content=models_list)
# COST # COST
costs = credits_config['costs'] costs = credits_config['costs']
cost = costs['other'] cost = costs['other']
@ -106,6 +101,8 @@ async def handle(incoming_request):
# READY # READY
# payload['user'] = str(user['_id'])
if 'chat/completions' in path and not payload.get('stream') is True: if 'chat/completions' in path and not payload.get('stream') is True:
payload['stream'] = False payload['stream'] = False

View file

@ -1 +1 @@
1691546405.042006 1691460004.7354248

View file

@ -35,7 +35,7 @@ async def update_roles(mongo):
for role in level_role_names: for role in level_role_names:
if role in role_names: if role in role_names:
users.update_one( users.update_one(
{'auth.discord': discord}, {'auth.discord': int(discord)},
{'$set': {'level': role}} {'$set': {'level': role}}
) )
print(f'Updated {discord} to {role}') print(f'Updated {discord} to {role}')

View file

@ -40,6 +40,11 @@ def test_server():
def test_api(model: str=MODEL, messages: List[dict]=None) -> dict: def test_api(model: str=MODEL, messages: List[dict]=None) -> dict:
"""Tests an API api_endpoint.""" """Tests an API api_endpoint."""
headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + closedai.api_key
}
json_data = { json_data = {
'model': model, 'model': model,
'messages': messages or MESSAGES, 'messages': messages or MESSAGES,
@ -48,7 +53,7 @@ def test_api(model: str=MODEL, messages: List[dict]=None) -> dict:
response = httpx.post( response = httpx.post(
url=f'{api_endpoint}/chat/completions', url=f'{api_endpoint}/chat/completions',
headers=HEADERS, headers=headers,
json=json_data, json=json_data,
timeout=20 timeout=20
) )
@ -69,30 +74,25 @@ def test_library():
def test_library_moderation(): def test_library_moderation():
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")
def test_models():
response = httpx.get(
url=f'{api_endpoint}/models',
headers=HEADERS,
timeout=5
)
response.raise_for_status()
return response.json()
def test_all(): def test_all():
"""Runs all tests.""" """Runs all tests."""
# print(test_server()) # print(test_server())
# print(test_api()) # print(test_api())
# print(test_library()) print(test_library())
# print(test_library_moderation()) # print(test_library_moderation())
print(test_models())
def test_api_moderation(model: str=MODEL, messages: List[dict]=None) -> dict: def test_api_moderation(model: str=MODEL, messages: List[dict]=None) -> dict:
"""Tests an API api_endpoint.""" """Tests an API api_endpoint."""
headers = {
'Authorization': 'Bearer ' + closedai.api_key
}
response = httpx.get( response = httpx.get(
url=f'{api_endpoint}/moderations', url=f'{api_endpoint}/moderations',
headers=HEADERS, headers=headers,
timeout=20 timeout=20
) )
response.raise_for_status() response.raise_for_status()
@ -104,9 +104,4 @@ if __name__ == '__main__':
closedai.api_base = api_endpoint closedai.api_base = api_endpoint
closedai.api_key = os.getenv('TEST_NOVA_KEY') closedai.api_key = os.getenv('TEST_NOVA_KEY')
HEADERS = {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + closedai.api_key
}
test_all() test_all()