[New Feature] Rest API implementation to showcase the OpenDBM features
This commit is contained in:
0
rest_api/app/services/__init__.py
Normal file
0
rest_api/app/services/__init__.py
Normal file
0
rest_api/app/services/auth/__init__.py
Normal file
0
rest_api/app/services/auth/__init__.py
Normal file
94
rest_api/app/services/auth/auth.py
Normal file
94
rest_api/app/services/auth/auth.py
Normal file
@@ -0,0 +1,94 @@
|
||||
from datetime import datetime, timedelta
|
||||
from schemas.user import User, UserInDB
|
||||
from schemas.token import Token, TokenData
|
||||
from services.main import OpenDBMSessionContext
|
||||
from config.db import get_db
|
||||
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
|
||||
from fastapi import Depends, HTTPException, status
|
||||
from passlib.context import CryptContext
|
||||
from jose import JWTError, jwt
|
||||
from typing import Union
|
||||
import os
|
||||
from dotenv import load_dotenv
|
||||
|
||||
load_dotenv()
|
||||
|
||||
|
||||
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="odbm/v1/login")
|
||||
SECRET_KEY = os.getenv('JWT_SECRET', 'DUMMY_SECRET')
|
||||
ALGORITHM = "HS256"
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv('TOKEN_EXPIRE', 30))
|
||||
|
||||
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
||||
db = get_db()
|
||||
|
||||
def get_user(username: str):
|
||||
if username in db:
|
||||
user_dict = db[username]
|
||||
return UserInDB(**user_dict)
|
||||
|
||||
def verify_password(plain_password, hashed_password):
|
||||
return pwd_context.verify(plain_password, hashed_password)
|
||||
|
||||
|
||||
def get_password_hash(password):
|
||||
return pwd_context.hash(password)
|
||||
|
||||
def authenticate_user(username: str, password: str):
|
||||
user = get_user(username)
|
||||
if not user:
|
||||
return False
|
||||
if not verify_password(password, user.hashed_password):
|
||||
return False
|
||||
return user
|
||||
|
||||
def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None):
|
||||
to_encode = data.copy()
|
||||
if expires_delta:
|
||||
expire = datetime.utcnow() + expires_delta
|
||||
else:
|
||||
expire = datetime.utcnow() + timedelta(minutes=15)
|
||||
to_encode.update({"exp": expire})
|
||||
encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
|
||||
return encoded_jwt
|
||||
|
||||
async def get_current_user(token: str = Depends(oauth2_scheme)):
|
||||
credentials_exception = HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Could not validate credentials",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
try:
|
||||
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
|
||||
username: str = payload.get("sub")
|
||||
if username is None:
|
||||
raise credentials_exception
|
||||
token_data = TokenData(username=username)
|
||||
except JWTError:
|
||||
raise credentials_exception
|
||||
user = get_user(username=token_data.username)
|
||||
if user is None:
|
||||
raise credentials_exception
|
||||
return user
|
||||
|
||||
async def get_current_active_user(current_user: User = Depends(get_current_user)):
|
||||
if current_user.disabled:
|
||||
raise HTTPException(status_code=400, detail="Inactive user")
|
||||
return current_user
|
||||
|
||||
def login(form_data: OAuth2PasswordRequestForm):
|
||||
hashed_pwd = get_password_hash(form_data.password)
|
||||
user = authenticate_user(form_data.username, form_data.password)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Bearer"},
|
||||
)
|
||||
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
||||
access_token = create_access_token(
|
||||
data={"sub": user.username}, expires_delta=access_token_expires
|
||||
)
|
||||
token = Token(access_token=access_token, token_type="bearer")
|
||||
return token
|
||||
|
||||
0
rest_api/app/services/biomaker/__init__.py
Normal file
0
rest_api/app/services/biomaker/__init__.py
Normal file
129
rest_api/app/services/biomaker/biomaker.py
Normal file
129
rest_api/app/services/biomaker/biomaker.py
Normal file
@@ -0,0 +1,129 @@
|
||||
import os
|
||||
from ast import For
|
||||
from zipfile import ZipFile
|
||||
|
||||
from schemas.biomaker_request import BiomakerRequest
|
||||
|
||||
from opendbm import FacialActivity, Movement, Speech, VerbalAcoustics
|
||||
|
||||
|
||||
class BiomakerService:
|
||||
def process(self, group: str, biomaker_request: BiomakerRequest):
|
||||
if group == "facial":
|
||||
return self.process_facial(group, biomaker_request)
|
||||
elif group == "acoustic":
|
||||
return self.process_acoustic(group, biomaker_request)
|
||||
elif group == "movement":
|
||||
return self.process_movement(group, biomaker_request)
|
||||
elif group == "speech":
|
||||
return self.process_speech(group, biomaker_request)
|
||||
pass
|
||||
|
||||
def process_facial(self, group, biomaker_request: BiomakerRequest):
|
||||
m = FacialActivity()
|
||||
curWorkingDir = os.getcwd()
|
||||
methodName = "process_facial"
|
||||
testfile = f"{curWorkingDir}/{biomaker_request.file_url}"
|
||||
if os.path.isfile(testfile):
|
||||
print("File exist")
|
||||
else:
|
||||
print("File not exist")
|
||||
m.fit(testfile)
|
||||
zip_filename = f"{curWorkingDir}/files/${methodName}"
|
||||
zipObj = ZipFile(zip_filename, "w")
|
||||
for var in biomaker_request.variables:
|
||||
if var == "landmark":
|
||||
lmk = m.get_landmark()
|
||||
lmk.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "asymmetry":
|
||||
asym = m.get_asymmetry()
|
||||
asym.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "expressivity":
|
||||
expr = m.get_expressivity()
|
||||
expr.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "action_unit":
|
||||
au = m.get_action_unit()
|
||||
au.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
zipObj.close()
|
||||
return zip_filename, methodName
|
||||
|
||||
def process_acoustic(self, group, biomaker_request: BiomakerRequest):
|
||||
m = VerbalAcoustics()
|
||||
curWorkingDir = os.getcwd()
|
||||
methodName = "process_acoustic"
|
||||
testfile = f"{curWorkingDir}/{biomaker_request.file_url}"
|
||||
m.fit(testfile)
|
||||
zip_filename = f"{curWorkingDir}/files/${methodName}"
|
||||
zipObj = ZipFile(zip_filename, "w")
|
||||
for var in biomaker_request.variables:
|
||||
if var == "audio_intensity":
|
||||
au = m.get_audio_intensity()
|
||||
au.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "pitch_frequency":
|
||||
vp = m.get_pitch_frequency()
|
||||
vp.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "formant_frequency":
|
||||
ff = m.get_formant_frequency()
|
||||
ff.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "harmonic_noise":
|
||||
hn = m.get_harmonic_noise()
|
||||
hn.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
zipObj.close()
|
||||
return zip_filename, methodName
|
||||
|
||||
def process_movement(self, group, biomaker_request: BiomakerRequest):
|
||||
m = Movement()
|
||||
curWorkingDir = os.getcwd()
|
||||
methodName = "process_movement"
|
||||
testfile = f"{curWorkingDir}/{biomaker_request.file_url}"
|
||||
m.fit(testfile)
|
||||
zip_filename = f"{curWorkingDir}/files/${methodName}"
|
||||
zipObj = ZipFile(zip_filename, "w")
|
||||
|
||||
for var in biomaker_request.variables:
|
||||
if var == "head_movement":
|
||||
lmk = m.get_head_movement()
|
||||
lmk.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "eye_blink":
|
||||
asym = m.get_eye_blink()
|
||||
asym.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "facial_tremor":
|
||||
au = m.get_facial_tremor()
|
||||
au.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "vocal_tremor":
|
||||
au = m.get_vocal_tremor()
|
||||
au.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
|
||||
return zip_filename, methodName
|
||||
|
||||
def process_speech(self, group, biomaker_request: BiomakerRequest):
|
||||
m = Speech()
|
||||
curWorkingDir = os.getcwd()
|
||||
methodName = "process_speech"
|
||||
testfile = f"{curWorkingDir}/{biomaker_request.file_url}"
|
||||
m.fit(testfile)
|
||||
zip_filename = f"{curWorkingDir}/files/${methodName}"
|
||||
zipObj = ZipFile(zip_filename, "w")
|
||||
for var in biomaker_request.variables:
|
||||
if var == "speech_features":
|
||||
sf = m.get_speech_features()
|
||||
sf.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
if var == "transcribe":
|
||||
tr = m.get_transcribe()
|
||||
tr.to_dataframe().to_csv(var + ".csv", index=False)
|
||||
zipObj.write(var + ".csv")
|
||||
zipObj.close()
|
||||
return zip_filename, methodName
|
||||
0
rest_api/app/services/file/__init__.py
Normal file
0
rest_api/app/services/file/__init__.py
Normal file
53
rest_api/app/services/file/file.py
Normal file
53
rest_api/app/services/file/file.py
Normal file
@@ -0,0 +1,53 @@
|
||||
import os
|
||||
import shutil
|
||||
from fastapi import UploadFile
|
||||
import boto3
|
||||
|
||||
from schemas.file_properties import FileProperties
|
||||
from services.file.i_file import FileService
|
||||
|
||||
AWS_ACCESS_KEY = os.getenv('AWS_ACCESS_KEY', 'DUMMY_KEY')
|
||||
AWS_SECRET_KEY = os.getenv('AWS_SECRET_KEY', 'DUMMY_SECRET')
|
||||
S3_BUCKET_NAME = 'odbm-test'
|
||||
|
||||
def get_file_service(platform:str) -> FileService:
|
||||
if platform.lower() == 's3':
|
||||
return S3FileService()
|
||||
else:
|
||||
return MemoryFileService()
|
||||
|
||||
|
||||
client = boto3.client(
|
||||
's3',
|
||||
aws_access_key_id=AWS_ACCESS_KEY,
|
||||
aws_secret_access_key=AWS_SECRET_KEY
|
||||
)
|
||||
|
||||
s3 = boto3.resource(
|
||||
's3',
|
||||
aws_access_key_id=AWS_ACCESS_KEY,
|
||||
aws_secret_access_key=AWS_SECRET_KEY
|
||||
)
|
||||
|
||||
class S3FileService(FileService):
|
||||
def upload(self, file_properties: FileProperties, file: UploadFile):
|
||||
print(AWS_ACCESS_KEY)
|
||||
print(AWS_SECRET_KEY)
|
||||
s3 = boto3.resource("s3")
|
||||
bucket = s3.Bucket(S3_BUCKET_NAME)
|
||||
bucket.upload_fileobj(file.file, file.filename, ExtraArgs={"ACL": "public-read"})
|
||||
uploaded_file_url = f"https://{S3_BUCKET_NAME}.s3.amazonaws.com/{file.filename}"
|
||||
return {"returnUrl": uploaded_file_url}
|
||||
|
||||
def download(file_properties: FileProperties):
|
||||
pass
|
||||
|
||||
class MemoryFileService(FileService):
|
||||
def upload(self, file_properties: FileProperties, file: UploadFile):
|
||||
file_location = f"files/{file.filename}"
|
||||
with open(file_location, "wb+") as file_object:
|
||||
shutil.copyfileobj(file.file, file_object)
|
||||
return {"info": f"file '{file.filename}' saved at '{file_location}'"}
|
||||
|
||||
def download(file_properties: FileProperties):
|
||||
pass
|
||||
13
rest_api/app/services/file/i_file.py
Normal file
13
rest_api/app/services/file/i_file.py
Normal file
@@ -0,0 +1,13 @@
|
||||
from fastapi import UploadFile
|
||||
from abc import ABCMeta, abstractmethod
|
||||
from schemas.file_properties import FileProperties
|
||||
|
||||
|
||||
class FileService:
|
||||
__metaclass__ = ABCMeta
|
||||
|
||||
@abstractmethod
|
||||
def upload(file_properties: FileProperties, file: UploadFile): raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def download(file_properties: FileProperties): raise NotImplementedError
|
||||
20
rest_api/app/services/main.py
Normal file
20
rest_api/app/services/main.py
Normal file
@@ -0,0 +1,20 @@
|
||||
from sqlalchemy.orm import Session
|
||||
from config.db import get_db
|
||||
|
||||
user_db = get_db()
|
||||
|
||||
class DBSessionContext(object):
|
||||
def __init__(self, db: Session):
|
||||
self.db = db
|
||||
|
||||
|
||||
class AppService(DBSessionContext):
|
||||
pass
|
||||
|
||||
|
||||
class AppCRUD(DBSessionContext):
|
||||
pass
|
||||
|
||||
class OpenDBMSessionContext(object):
|
||||
def __init__(self):
|
||||
self.db = user_db
|
||||
Reference in New Issue
Block a user