Skip to content

Commit

Permalink
Merge pull request #15 from prentice-jobs/feat/integration-ml
Browse files Browse the repository at this point in the history
Feat: RecSys integration to Backend
  • Loading branch information
jeremyalv authored Jun 20, 2024
2 parents 5f4fb2c + 6ea2ec1 commit 8e39ef5
Show file tree
Hide file tree
Showing 25 changed files with 1,296 additions and 60 deletions.
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@ POSTGRES_DB_NAME=
POSTGRES_DB_USER=
POSTGRES_DB_PASSWORD=

GCS_BUCKET_OFFER_LETTER=
# CLOUD STORAGE
GCS_BUCKET_OFFER_LETTER=
GCS_BUCKET_STOPWORDS=
GCS_BUCKET_RECSYS=
69 changes: 69 additions & 0 deletions alembic/versions/0b7939b453d5_create_recsys_sim_scores_and_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""create recsys sim_scores and recommendation cache tables
Revision ID: 0b7939b453d5
Revises: fa73e6dafaad
Create Date: 2024-06-18 13:34:44.532365
"""
from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision: str = '0b7939b453d5'
down_revision: Union[str, None] = 'fa73e6dafaad'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
op.create_table(
'user_review_similarity_scores',
sa.Column('id', sa.UUID(), autoincrement=False),
sa.Column('created_at', sa.TIMESTAMP(timezone=True)),
sa.Column('updated_at', sa.TIMESTAMP(timezone=True)),
sa.Column('is_deleted', sa.Boolean()),

sa.Column('user_id', sa.UUID()),
sa.Column('review_id', sa.UUID()),
sa.Column('sim_score', sa.Float(precision=3)),

sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(
["user_id"], ["users.id"],
name="fk_sim_scores_user",
),
sa.ForeignKeyConstraint(
["review_id"], ["company_reviews.id"],
name="fk_sim_scores_review",
)
)

op.create_table(
'user_review_recommendations_cache',
sa.Column('id', sa.UUID(), autoincrement=False),
sa.Column('created_at', sa.TIMESTAMP(timezone=True)),
sa.Column('updated_at', sa.TIMESTAMP(timezone=True)),
sa.Column('is_deleted', sa.Boolean()),

sa.Column('user_id', sa.UUID()),
sa.Column('review_id', sa.UUID()),
sa.Column('sim_score', sa.Float(precision=3)),

sa.PrimaryKeyConstraint('id'),
sa.ForeignKeyConstraint(
["user_id"], ["users.id"],
name="fk_sim_scores_user",
),
sa.ForeignKeyConstraint(
["review_id"], ["company_reviews.id"],
name="fk_sim_scores_review",
)
)


def downgrade() -> None:
op.drop_table('user_review_recommendations_cache')
op.drop_table('user_review_similarity_scores')
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ def upgrade() -> None:
sa.Column('updated_at', sa.TIMESTAMP(timezone=True)),
sa.Column('is_deleted', sa.Boolean()),

sa.Column('role', sa.String(255), nullable=True),
sa.Column('industry', sa.String(255), nullable=True),
sa.Column('location', sa.String(255), nullable=True),
sa.Column('role', sa.String(255)),
sa.Column('industry', sa.String(255)),
sa.Column('location', sa.String(255)),

sa.Column('user_id', sa.UUID(), nullable=False),

Expand Down
2 changes: 2 additions & 0 deletions alembic/versions/d5d068b44817_add_company_reviews_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ def upgrade() -> None:
sa.Column('offer_letter_url', sa.String()),
sa.Column('annual_salary', sa.BigInteger()),
sa.Column('salary_currency', sa.String(3)),

sa.PrimaryKeyConstraint('id'),
)


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ def upgrade() -> None:
sa.Column('review_id', sa.UUID()),
sa.Column('sentiment_score', sa.SmallInteger()),
sa.Column('sentiment', sa.String(30)),

sa.PrimaryKeyConstraint('id'),
)

op.create_table(
Expand All @@ -41,7 +43,9 @@ def upgrade() -> None:
sa.Column('review_id', sa.UUID()),
sa.Column('author_id', sa.UUID()),
sa.Column('likes_count', sa.Integer()),
sa.Column('content', sa.String(1000))
sa.Column('content', sa.String(1000)),

sa.PrimaryKeyConstraint('id'),
)

op.create_table(
Expand All @@ -53,6 +57,8 @@ def upgrade() -> None:

sa.Column('review_comment_id', sa.UUID()),
sa.Column('liker_id', sa.UUID()),

sa.PrimaryKeyConstraint('id'),
)


Expand Down
9 changes: 9 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,16 @@ httptools==0.6.1
httpx==0.27.0
idna==3.7
Jinja2==3.1.4
joblib==1.4.2
logger==1.4
Mako==1.3.5
markdown-it-py==3.0.0
MarkupSafe==2.1.5
mdurl==0.1.2
msgpack==1.0.8
numpy==2.0.0
orjson==3.10.3
pandas==2.2.2
proto-plus==1.23.0
protobuf==4.25.3
psycopg2==2.9.9
Expand All @@ -50,19 +53,25 @@ pydantic_core==2.18.2
Pygments==2.18.0
PyJWT==2.8.0
pyparsing==3.1.2
python-dateutil==2.9.0.post0
python-dotenv==1.0.1
python-multipart==0.0.9
pytz==2024.1
PyYAML==6.0.1
requests==2.32.3
rich==13.7.1
rsa==4.9
scikit-learn==1.5.0
scipy==1.13.1
shellingham==1.5.4
six==1.16.0
sniffio==1.3.1
SQLAlchemy==2.0.30
starlette==0.37.2
threadpoolctl==3.5.0
typer==0.12.3
typing_extensions==4.11.0
tzdata==2024.1
ujson==5.10.0
uritemplate==4.1.1
urllib3==2.2.1
Expand Down
3 changes: 2 additions & 1 deletion src/account/constants/messages.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
SERVICE_CREATE_USER_SUCCESS = "Successfully created user."
CREATE_NEW_USER_SUCCESS = "Successfully created user."
SAVE_USER_PREFERENCES_SUCCESS = "Successfully saved user preferences."

UNAUTHORIZED_ACTION = "Unauthorized: Failed to perform this operation."
UNAUTHORIZED_ACTION_RECOMMENDATION = "You are not logged in. Try logging in with the required permissions."
40 changes: 37 additions & 3 deletions src/account/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
from src.account.schema import (
CheckUserRegisteredSchema,
RegisterSchema,
UserPreferencesSchema,
)

from src.account.service import AccountService
from src.account.security import get_current_user
from src.account.exceptions import (
UserAlreadyExistsException,
RegistrationFailedException
RegistrationFailedException,
SavePreferencesFailedException,
UserPreferencesAlreadyExistsException,
)

VERSION = "v1"
Expand All @@ -44,7 +47,7 @@
@account_router.post("/exists", status_code=HTTPStatus.OK, response_model=bool)
def check_user_registered(
payload: CheckUserRegisteredSchema = Body(),
session = Depends(get_db),
session: Session = Depends(get_db),
):
is_registered = AccountService.check_user_is_registered(
session=session,
Expand All @@ -56,7 +59,7 @@ def check_user_registered(
@account_router.post("/register", status_code=HTTPStatus.CREATED, response_model=GenericAPIResponseModel)
def register(
payload: RegisterSchema = Body(),
session = Depends(get_db),
session: Session = Depends(get_db),
):
try:
response: GenericAPIResponseModel = AccountService.register_user(session=session, payload=payload)
Expand All @@ -81,6 +84,37 @@ def register(

return build_api_response(response)

@account_router.post("/preferences", status_code=HTTPStatus.OK, response_model=GenericAPIResponseModel)
def save_user_preferences(
payload: UserPreferencesSchema = Body(),
session: Session = Depends(get_db),
user: User = Depends(get_current_user),
):
try:
response: GenericAPIResponseModel = AccountService.save_user_preferences(
payload=payload,
session=session,
user=user,
)

return build_api_response(response)
except UserPreferencesAlreadyExistsException as err:
response = GenericAPIResponseModel(
status=HTTPStatus.CONFLICT,
message=err.message,
error=err.message,
)

return build_api_response(response)
except SavePreferencesFailedException as err:
response = GenericAPIResponseModel(
status=HTTPStatus.INTERNAL_SERVER_ERROR,
message=err.message,
error=err.message,
)

return build_api_response(response)

@account_router.get("/", status_code=HTTPStatus.OK)
def fetch_user_info(
prentice_user: User = Depends(get_current_user),
Expand Down
10 changes: 10 additions & 0 deletions src/account/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ def __init__(self, message="Error while registering new user"):
super().__init__(message)
self.message = message

class UserPreferencesAlreadyExistsException(Exception):
def __init__(self, message="User already has a preference setting!"):
super().__init__(message)
self.message = message

class SavePreferencesFailedException(Exception):
def __init__(self, message="Error while saving user preferences"):
super().__init__(message)
self.message = message

class FirebaseTokenVerificationException(HTTPException):
def __init__(
self,
Expand Down
7 changes: 3 additions & 4 deletions src/account/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ class User(PrenticeBaseModel):
class UserPreferences(PrenticeBaseModel):
__tablename__ = "user_preferences"

role = Column(String(255), nullable=True)
industry = Column(String(255), nullable=True)
location = Column(String(255), nullable=True)
is_active = Column(Boolean)
role = Column(String(255))
industry = Column(String(255))
location = Column(String(255))

user_id = Column(UUID(as_uuid=True), ForeignKey("users.id"))
user = relationship(
Expand Down
14 changes: 13 additions & 1 deletion src/account/schema.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
from datetime import datetime
from typing import Optional
from typing_extensions import Annotated
from pydantic import (
UUID4,
BaseModel,
EmailStr
EmailStr,
Field,
)

from src.core.schema import (
Expand All @@ -20,6 +22,16 @@ class RegisterSchema(BaseModel):
photo_url: Optional[str]
email_verified: bool

class UserPreferencesSchema(BaseModel):
# https://stackoverflow.com/questions/61326020/how-can-i-set-max-string-field-length-constraint-in-pydantic
# Setting max length to avoid DB insertion errors
role: str = Field(..., max_length=255)
industry: str = Field(..., max_length=255)
location: str = Field(..., max_length=255)

class UserPreferencesResponseSchema(UserPreferencesSchema, PrenticeBaseSchema):
user_id: UUID4

class RegisterResponseSchema(BaseModel):
email: EmailStr
created_at: datetime
Expand Down
Loading

0 comments on commit 8e39ef5

Please sign in to comment.