mirror of
https://github.com/NovaOSS/nova-api.git
synced 2024-11-25 22:33:57 +01:00
Compare commits
No commits in common. "d3d9ead8f448e90a25bc8acd77b9c9eb154c2375" and "0d0453291f385b93d98ebcaa86c5a7e5ee3ff1d6" have entirely different histories.
d3d9ead8f4
...
0d0453291f
|
@ -4,7 +4,7 @@
|
||||||
# git commit -am "Auto-trigger - Production server started" && git push origin Production
|
# git commit -am "Auto-trigger - Production server started" && git push origin Production
|
||||||
|
|
||||||
# backup database
|
# backup database
|
||||||
/usr/local/bin/python /home/nova-api/api/backup_manager/main.py pre_prodpush
|
/usr/local/bin/python /home/nova-api/backup_manager/main.py pre_prodpush
|
||||||
|
|
||||||
# Kill production server
|
# Kill production server
|
||||||
fuser -k 2333/tcp
|
fuser -k 2333/tcp
|
||||||
|
|
|
@ -1,22 +1,21 @@
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from sys import argv
|
|
||||||
from bson import json_util
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
from motor.motor_asyncio import AsyncIOMotorClient
|
from motor.motor_asyncio import AsyncIOMotorClient
|
||||||
|
from bson import json_util
|
||||||
|
import json
|
||||||
|
from sys import argv
|
||||||
|
import asyncio
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
MONGO_URI = os.environ['MONGO_URI']
|
MONGO_URI = os.getenv("MONGO_URI")
|
||||||
FILE_DIR = os.path.dirname(os.path.realpath(__file__))
|
FILE_DIR = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
|
||||||
async def main(output_dir: str):
|
async def main(output_dir):
|
||||||
await make_backup(output_dir)
|
await make_backup(output_dir)
|
||||||
|
|
||||||
async def make_backup(output_dir: str):
|
async def make_backup(output_dir):
|
||||||
output_dir = os.path.join(FILE_DIR, '..', 'backups', output_dir)
|
output_dir = os.path.join(FILE_DIR, "..", "backups", output_dir)
|
||||||
|
|
||||||
if not os.path.exists(output_dir):
|
if not os.path.exists(output_dir):
|
||||||
os.makedirs(output_dir)
|
os.makedirs(output_dir)
|
||||||
|
@ -26,29 +25,26 @@ async def make_backup(output_dir: str):
|
||||||
databases = {db: await client[db].list_collection_names() for db in databases}
|
databases = {db: await client[db].list_collection_names() for db in databases}
|
||||||
|
|
||||||
for database in databases:
|
for database in databases:
|
||||||
if database == 'local':
|
if not os.path.exists(f"{output_dir}/{database}"):
|
||||||
continue
|
os.mkdir(f"{output_dir}/{database}")
|
||||||
|
|
||||||
if not os.path.exists(f'{output_dir}/{database}'):
|
|
||||||
os.mkdir(f'{output_dir}/{database}')
|
|
||||||
|
|
||||||
for collection in databases[database]:
|
for collection in databases[database]:
|
||||||
print(f'Making backup for {database}/{collection}')
|
print(f"Making backup for {database}/{collection}")
|
||||||
await make_backup_for_collection(database, collection, output_dir)
|
await make_backup_for_collection(database, collection, output_dir)
|
||||||
|
|
||||||
async def make_backup_for_collection(database, collection, output_dir):
|
async def make_backup_for_collection(database, collection, output_dir):
|
||||||
path = f'{output_dir}/{database}/{collection}.json'
|
path = f"{output_dir}/{database}/{collection}.json"
|
||||||
|
|
||||||
client = AsyncIOMotorClient(MONGO_URI)
|
client = AsyncIOMotorClient(MONGO_URI)
|
||||||
collection = client[database][collection]
|
collection = client[database][collection]
|
||||||
documents = await collection.find({}).to_list(length=None)
|
documents = await collection.find({}).to_list(length=None)
|
||||||
|
|
||||||
with open(path, 'w') as f:
|
with open(path, "w") as f:
|
||||||
json.dump(documents, f, default=json_util.default)
|
json.dump(documents, f, default=json_util.default)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == "__main__":
|
||||||
if len(argv) < 2 or len(argv) > 2:
|
if len(argv) < 2 or len(argv) > 2:
|
||||||
print('Usage: python3 main.py <output_dir>')
|
print("Usage: python3 main.py <output_dir>")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
output_dir = argv[1]
|
output_dir = argv[1]
|
||||||
|
|
1
api/cache/crypto_prices.json
vendored
1
api/cache/crypto_prices.json
vendored
|
@ -1 +0,0 @@
|
||||||
{"LTC": 64.665, "_last_updated": 1695334741.4905503, "BTC": 26583.485, "MATIC": 0.52075, "XMR": 146.46058828041404, "ADA": 0.2455, "USDT": 1.000005, "ETH": 1586.115, "USD": 1.0, "EUR": 1.0662838016640013}
|
|
68
api/core.py
68
api/core.py
|
@ -8,12 +8,9 @@ sys.path.append(project_root)
|
||||||
|
|
||||||
# the code above is to allow importing from the root folder
|
# the code above is to allow importing from the root folder
|
||||||
|
|
||||||
import time
|
|
||||||
import json
|
import json
|
||||||
import hmac
|
import hmac
|
||||||
import httpx
|
|
||||||
import fastapi
|
import fastapi
|
||||||
import functools
|
|
||||||
|
|
||||||
from dhooks import Webhook, Embed
|
from dhooks import Webhook, Embed
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
@ -21,7 +18,7 @@ from dotenv import load_dotenv
|
||||||
import checks.client
|
import checks.client
|
||||||
|
|
||||||
from helpers import errors
|
from helpers import errors
|
||||||
from db import users, finances
|
from db.users import UserManager
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
router = fastapi.APIRouter(tags=['core'])
|
router = fastapi.APIRouter(tags=['core'])
|
||||||
|
@ -65,7 +62,9 @@ async def get_users(discord_id: int, incoming_request: fastapi.Request):
|
||||||
auth = await check_core_auth(incoming_request)
|
auth = await check_core_auth(incoming_request)
|
||||||
if auth: return auth
|
if auth: return auth
|
||||||
|
|
||||||
user = await users.manager.user_by_discord_id(discord_id)
|
# Get user by discord ID
|
||||||
|
manager = UserManager()
|
||||||
|
user = await manager.user_by_discord_id(discord_id)
|
||||||
if not user:
|
if not user:
|
||||||
return await errors.error(404, 'Discord user not found in the API database.', 'Check the `discord_id` parameter.')
|
return await errors.error(404, 'Discord user not found in the API database.', 'Check the `discord_id` parameter.')
|
||||||
|
|
||||||
|
@ -89,7 +88,9 @@ async def create_user(incoming_request: fastapi.Request):
|
||||||
except (json.decoder.JSONDecodeError, AttributeError):
|
except (json.decoder.JSONDecodeError, AttributeError):
|
||||||
return await errors.error(400, 'Invalid or no payload received.', 'The payload must be a JSON object with a `discord_id` key.')
|
return await errors.error(400, 'Invalid or no payload received.', 'The payload must be a JSON object with a `discord_id` key.')
|
||||||
|
|
||||||
user = await users.manager.create(discord_id)
|
# Create the user
|
||||||
|
manager = UserManager()
|
||||||
|
user = await manager.create(discord_id)
|
||||||
await new_user_webhook(user)
|
await new_user_webhook(user)
|
||||||
|
|
||||||
user['_id'] = str(user['_id'])
|
user['_id'] = str(user['_id'])
|
||||||
|
@ -113,7 +114,9 @@ async def update_user(incoming_request: fastapi.Request):
|
||||||
'The payload must be a JSON object with a `discord_id` key and an `updates` key.'
|
'The payload must be a JSON object with a `discord_id` key and an `updates` key.'
|
||||||
)
|
)
|
||||||
|
|
||||||
user = await users.manager.update_by_discord_id(discord_id, updates)
|
# Update the user
|
||||||
|
manager = UserManager()
|
||||||
|
user = await manager.update_by_discord_id(discord_id, updates)
|
||||||
|
|
||||||
return user
|
return user
|
||||||
|
|
||||||
|
@ -144,54 +147,3 @@ async def run_checks(incoming_request: fastapi.Request):
|
||||||
results[func.__name__] = result
|
results[func.__name__] = result
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
async def get_crypto_price(cryptocurrency: str) -> float:
|
|
||||||
"""Gets the price of a cryptocurrency using coinbase's API."""
|
|
||||||
|
|
||||||
if os.path.exists('cache/crypto_prices.json'):
|
|
||||||
with open('cache/crypto_prices.json', 'r') as f:
|
|
||||||
cache = json.load(f)
|
|
||||||
else:
|
|
||||||
cache = {}
|
|
||||||
|
|
||||||
is_old = time.time() - cache.get('_last_updated', 0) > 60 * 60
|
|
||||||
|
|
||||||
if is_old or cryptocurrency not in cache:
|
|
||||||
async with httpx.AsyncClient() as client:
|
|
||||||
response = await client.get(f'https://api.coinbase.com/v2/prices/{cryptocurrency}-USD/spot')
|
|
||||||
usd_price = float(response.json()['data']['amount'])
|
|
||||||
|
|
||||||
cache[cryptocurrency] = usd_price
|
|
||||||
cache['_last_updated'] = time.time()
|
|
||||||
|
|
||||||
with open('cache/crypto_prices.json', 'w') as f:
|
|
||||||
json.dump(cache, f)
|
|
||||||
|
|
||||||
return cache[cryptocurrency]
|
|
||||||
|
|
||||||
@router.get('/finances')
|
|
||||||
async def get_finances(incoming_request: fastapi.Request):
|
|
||||||
"""Return financial information. Requires a core API key."""
|
|
||||||
|
|
||||||
auth_error = await check_core_auth(incoming_request)
|
|
||||||
if auth_error: return auth_error
|
|
||||||
|
|
||||||
transactions = await finances.manager.get_entire_financial_history()
|
|
||||||
|
|
||||||
for table in transactions:
|
|
||||||
for transaction in transactions[table]:
|
|
||||||
currency = transaction['currency']
|
|
||||||
|
|
||||||
if '-' in currency:
|
|
||||||
currency = currency.split('-')[0]
|
|
||||||
|
|
||||||
amount = transaction['amount']
|
|
||||||
|
|
||||||
if currency == 'mBTC':
|
|
||||||
currency = 'BTC'
|
|
||||||
amount = transaction['amount'] / 1000
|
|
||||||
|
|
||||||
amount_in_usd = await get_crypto_price(currency) * amount
|
|
||||||
transactions[table][transactions[table].index(transaction)]['amount_usd'] = amount_in_usd
|
|
||||||
|
|
||||||
return transactions
|
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import os
|
|
||||||
import asyncio
|
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
|
||||||
from motor.motor_asyncio import AsyncIOMotorClient
|
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
class FinanceManager:
|
|
||||||
def __init__(self):
|
|
||||||
self.conn = AsyncIOMotorClient(os.environ['MONGO_URI'])
|
|
||||||
|
|
||||||
async def _get_collection(self, collection_name: str):
|
|
||||||
return self.conn['finances'][collection_name]
|
|
||||||
|
|
||||||
async def get_entire_financial_history(self):
|
|
||||||
donations_db = await self._get_collection('donations')
|
|
||||||
expenses_db = await self._get_collection('expenses')
|
|
||||||
|
|
||||||
# turn both into JSON-like lists of dicts at once (make sure to fix the _id)
|
|
||||||
history = {'donations': [], 'expenses': []}
|
|
||||||
|
|
||||||
async for donation in donations_db.find():
|
|
||||||
donation['_id'] = str(donation['_id'])
|
|
||||||
history['donations'].append(donation)
|
|
||||||
|
|
||||||
async for expense in expenses_db.find():
|
|
||||||
expense['_id'] = str(expense['_id'])
|
|
||||||
history['expenses'].append(expense)
|
|
||||||
|
|
||||||
# sort all by timestamp
|
|
||||||
history['donations'] = sorted(history['donations'], key=lambda x: x['timestamp'])
|
|
||||||
|
|
||||||
return history
|
|
||||||
|
|
||||||
manager = FinanceManager()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
print(asyncio.run(manager.get_entire_financial_history()))
|
|
|
@ -19,8 +19,7 @@ from helpers import tokens, errors, network
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
users = UserManager()
|
users = UserManager()
|
||||||
models_list = json.load(open('cache/models.json', encoding='utf8'))
|
models_list = json.load(open('models.json', encoding='utf8'))
|
||||||
models = [model['id'] for model in models_list['data']]
|
|
||||||
|
|
||||||
with open('config/config.yml', encoding='utf8') as f:
|
with open('config/config.yml', encoding='utf8') as f:
|
||||||
config = yaml.safe_load(f)
|
config = yaml.safe_load(f)
|
||||||
|
@ -71,9 +70,6 @@ async def handle(incoming_request: fastapi.Request):
|
||||||
if ban_reason:
|
if ban_reason:
|
||||||
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.')
|
||||||
|
|
||||||
if 'account/credits' in path:
|
|
||||||
return fastapi.responses.JSONResponse({'credits': user['credits']})
|
|
||||||
|
|
||||||
costs = config['costs']
|
costs = config['costs']
|
||||||
cost = costs['other']
|
cost = costs['other']
|
||||||
|
|
||||||
|
@ -153,9 +149,6 @@ async def handle(incoming_request: fastapi.Request):
|
||||||
|
|
||||||
media_type = 'text/event-stream' if payload.get('stream', False) else 'application/json'
|
media_type = 'text/event-stream' if payload.get('stream', False) else 'application/json'
|
||||||
|
|
||||||
if (model := payload.get('model')) not in models and model is not None:
|
|
||||||
return await errors.error(404, 'Model not found.', 'Check the model name and try again.')
|
|
||||||
|
|
||||||
return fastapi.responses.StreamingResponse(
|
return fastapi.responses.StreamingResponse(
|
||||||
content=responder.respond(
|
content=responder.respond(
|
||||||
user=user,
|
user=user,
|
||||||
|
|
|
@ -217,8 +217,8 @@ async def demo():
|
||||||
print('Checking streamed chat completions...')
|
print('Checking streamed chat completions...')
|
||||||
print(await test_chat_stream_gpt3())
|
print(await test_chat_stream_gpt3())
|
||||||
|
|
||||||
# print('[lightblue]Checking if image generation works...')
|
print('[lightblue]Checking if image generation works...')
|
||||||
# print(await test_image_generation())
|
print(await test_image_generation())
|
||||||
|
|
||||||
print('Checking the models endpoint...')
|
print('Checking the models endpoint...')
|
||||||
print(await test_models())
|
print(await test_models())
|
||||||
|
|
Loading…
Reference in a new issue