Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion database.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

// Free to use remote db or create a local database. Modify the URl appropriately
# // Free to use remote db or create a local database. Modify the URl appropriately
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"

# Is responsible for FastApi to interact with database
engine = create_engine(SQLALCHEMY_DATABASE_URL)

# It is responsible for interacting with db
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

# It can be commonly used by all classes
Base = declarative_base()

143 changes: 129 additions & 14 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,151 @@
from typing import List
from fastapi import FastAPI, HTTPException, Depends
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from database import SessionLocal, engine, Base
import models, schemas

import logging

logging.basicConfig(
level=logging.INFO, # Adjust level as needed (DEBUG, INFO, etc.)
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
)
logger = logging.getLogger(__name__)

app = FastAPI()

Base.metadata.create_all(bind=engine)


def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()

@app.post("/users/", response_model=schemas.User)

@app.post("/create-user", response_model=schemas.User)
def create_user(user: schemas.UserCreate, db: Session = Depends(get_db)):
db_user = models.User(**user.dict())
db.add(db_user)
db.commit()
db.refresh(db_user)
return db_user
try:
logger.info("Creating new user with email: %s", user.email)
db_user = models.User(
name=user.name,
age=user.age,
gender=user.gender,
email=user.email,
city=user.city,
interests=user.interests
)
db.add(db_user)
db.commit()
db.refresh(db_user)
logger.info("User created successfully with id: %s", db_user.id)
return db_user
except IntegrityError as he:
db.rollback()
logger.warning("IntegrityError: %s", str(he))
raise HTTPException(status_code=409, detail="User with this email already exists")
except Exception as e:
logger.error("Error occurred while creating user: %s", str(e))
db.rollback()
raise HTTPException(status_code=500, detail="Internal Server Error while creating user ")


@app.get("/find-all-users", response_model=List[schemas.User])
def read_users(db: Session = Depends(get_db)):
try:
logger.info("Fetching all users")
users = db.query(models.User).all()
logger.info("Fetched %d users", len(users))
return users
except Exception as e:
logger.error("Error occurred while fetching users: %s", str(e))
raise HTTPException(status_code=500, detail="Internal Server Error while fetching users")

@app.get("/users/", response_model=list[schemas.User])
def read_users(skip: int = 0, limit: int = 10, db: Session = Depends(get_db)):
users = db.query(models.User).offset(skip).limit(limit).all()
return users

@app.get("/users/{user_id}", response_model=schemas.User)
def read_user(user_id: int, db: Session = Depends(get_db)):
user = db.query(models.User).filter(models.User.id == user_id).first()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
return user
try:
logger.info("Fetching user with id: %s", user_id)
user = db.query(models.User).filter(models.User.id == user_id).first()
if user is None:
logger.warning("User with id %s not found", user_id)
raise HTTPException(status_code=404, detail="User not found")
logger.info("User with id %s fetched successfully", user_id)
return user
except Exception as e:
logger.error("Error occurred while fetching user with id %s: %s", user_id, str(e))
raise HTTPException(status_code=500, detail="Internal Server Error while fetching user "+str(e))

# ssss
@app.get("/match", response_model=List[schemas.CandidateSuggestion])
def calculate_match(user_identifier: schemas.UserIdentifier, db: Session = Depends(get_db)):
try:
logger.info("Calculating match for user: %s", user_identifier.email)
# Retrieve the full user profile from the database using name and email
user = db.query(models.User).filter(
models.User.email == user_identifier.email,
models.User.name == user_identifier.name
).first()
if not user:
logger.warning("User not found with email: %s and name: %s", user_identifier.email, user_identifier.name)
raise HTTPException(status_code=404, detail="User not found")

# Get candidates of the opposite gender
candidates = db.query(models.User).filter(models.User.gender != user.gender).all()
if not candidates:
logger.warning("No matches found for user with email: %s", user_identifier.email)
raise HTTPException(status_code=404, detail="No matches found Dont worry you are unique in your own way")

suggestions = []
user_interests = set(user.interests)

for candidate in candidates:
candidate_interests = set(candidate.interests)
# Calculate interests similarity using Jaccard similarity
common_interests = user_interests.intersection(candidate_interests)
union_interests = user_interests.union(candidate_interests)
interest_score = len(common_interests) / len(union_interests) if union_interests else 0

# Calculate age compatibility: score decreases linearly with age difference (threshold 10 years)
age_diff = abs(candidate.age - user.age)
max_age_diff = 5
age_score = max(0, 1 - (age_diff / max_age_diff))

# City match: bonus if same city (score 1 if same, 0 otherwise)
city_score = 1 if candidate.city.lower() == user.city.lower() else 0

# Weight factors for composite match_percentage
weight_interest = 0.5
weight_age = 0.3
weight_city = 0.2

total_score = (interest_score * weight_interest) + (age_score * weight_age) + (city_score * weight_city)
match_percentage = round(total_score * 100, 2) # Convert to percentage

candidate_suggestion = schemas.CandidateSuggestion(
id=candidate.id,
name=candidate.name,
email=candidate.email,
age=candidate.age,
gender=candidate.gender,
city=candidate.city,
interests=candidate.interests,
match_percentage=match_percentage
)
suggestions.append(candidate_suggestion)

# Sort suggestions by match_percentage in descending order and return the top 3
suggestions.sort(key=lambda x: x.match_percentage, reverse=True)
top_suggestions = suggestions[:3]
logger.info("Match calculation successful for user %s. Found %d suggestions.", user_identifier.email,
len(top_suggestions))
return top_suggestions

except HTTPException as he:
raise he
except Exception as e:
logger.error("Error occurred during match calculation: %s", str(e))
raise HTTPException(status_code=500, detail="Internal Server Error during match calculation")
10 changes: 8 additions & 2 deletions models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from sqlalchemy import Column, Integer, String, ARRAY
from database import Base
from database import Base, engine
from sqlalchemy.types import JSON


class User(Base):
__tablename__ = "users"
Expand All @@ -10,5 +12,9 @@ class User(Base):
gender = Column(String)
email = Column(String, unique=True, index=True)
city = Column(String, index=True)
interests = Column(ARRAY(String))
interests = Column(JSON)

# used to create tables in database

# Base.metadata.createAll(bird=engine)

24 changes: 24 additions & 0 deletions schemas.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from pydantic import BaseModel
from typing import List


class UserBase(BaseModel):
name: str
age: int
Expand All @@ -18,3 +19,26 @@ class User(UserBase):
class Config:
orm_mode = True

# New schema: used to identify a user by name and email
class UserIdentifier(BaseModel):
name: str
email: str



# Define the CandidateSuggestion schema for match suggestions
class CandidateSuggestion(BaseModel):
id: int
name: str
email: str
age: int
gender: str
city: str
interests: List[str]
match_percentage: float # Compatibility rating as a percentage

class Config:
orm_mode = True



Binary file added test.db
Binary file not shown.